home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 12 / Cream of the Crop 12 (Part II) / Cream of the Crop 12 (Part II).iso / OS2 / V15N04.ZIP / WARPCA.ZIP / WCABSRC.ZIP / WARPCAB.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-18  |  84.0 KB  |  3,459 lines

  1. /*********************************************************************
  2.     WARPCAB.CPP  --     Warp Cabinet-- A File Viewer using Borland's
  3.                             ObjectWindows Library (OWL) for OS/2 Warp.
  4.  
  5.                             (Uses Borland C++ for OS/2, v.2.x.)
  6.  
  7.                             v. 1.00 -- Source Code
  8.  
  9.                             PC Magazine,    (c)1996 -- Ziff-Davis Publishing Co.
  10.                                                 All rights reserved.
  11.                                                 First Published in PC Magazine,
  12.                                                 US Edition, Feb. 26, 1996.
  13.                                                 Written by Richard V. Dragan.
  14. **********************************************************************/
  15. #include <cstring.h>
  16. #include <assert.h>
  17. #include <process.h>
  18. #include <dir.h>
  19. #include <io.h>
  20. #include <stdio.h>
  21. #include <classlib\arrays.h>
  22. #include <owl\owlpch.h>
  23. #include <owl\applicat.h>
  24. #include <owl\decframe.h>
  25. #include <owl\gadget.h>
  26. #include <owl\textgadg.h>
  27. #include <owl\statusba.h>
  28. #include <owl\listbox.h>
  29. #include <owl\dialog.h>
  30. #include <owl\menu.h>
  31.  
  32. #include "os2api.h"
  33.  
  34. #include "resource.h"
  35. #include "fileasoc.h"
  36. #include "filentry.h"
  37. #include "filetool.h"
  38. #include "fileprop.h"
  39. #include "filechng.h"  // File Copy/Move/Rename/Delete dialog box
  40. #include "runcmd.h"    // Run a command in a dialog box
  41. #include "associat.h"  // Associations dialog box
  42. #include "creatdir.h"  // Create new dir. dialog
  43. #include "selfiles.h"  // Select files by mask.
  44. #include "filemask.h"  // Set File mask dialog
  45. #include "details.h"   // Select File Details dialog
  46. #include "confirm.h"   // Set Confirmation Options dialog
  47.  
  48. #define _DROP_API_ONLY_
  49. #include "do_drag.h"    // Drag-and-drop Direct Manipulation routines
  50. #undef _DROP_API_ONLY_
  51.  
  52. #pragma hdrstop
  53.  
  54. #define NO_BTN        0
  55. #define RIGHT_BTN    1
  56. #define LEFT_BTN    2
  57.  
  58. BOOL bContinueFileOp = TRUE;
  59.  
  60. // Object to store our list of associations--file types + programs that work with them.
  61. TISArrayAsVector <FILEASSOCIATION> FileAssociations(10, 0, 1);
  62. TISArrayAsVector <FILEENTRY> SelectedFileList(10, 0, 1);
  63. TISArrayAsVector <string> AllFilesList(10, 0, 1);
  64. // Dirs. that must be created (for copying, moving or renaming) or deleted for deleting.
  65. TISArrayAsVector <string> CriticalDirsList(8, 0, 1);
  66.  
  67. ULONG ulTotalFilesBytes = 0;
  68.  
  69. TStatusBar *pGlobalStatus = NULL;
  70. TTextGadget *pGlobalStatusBar = NULL;
  71. TWindow *pGlobalParent = NULL;
  72. HWND hwndGlobalParent = NULL;
  73.  
  74. HPOINTER hptrMove;
  75. HPOINTER hptrCopy;
  76. int bDragCopy;  // FALSE = MOVE
  77.  
  78. // Which files to show.
  79. char szMask[80];
  80. char szSelByMask[80];
  81. unsigned long ulShowAttrBits = 0;
  82. int bShowHiddenOrSysObjs = FALSE;
  83.  
  84. // Confirmation options.
  85. int bConfirmDelete = FALSE;
  86. int bConfirmReplace = FALSE;
  87. int bConfirmCopy = FALSE;
  88. int bConfirmAll = TRUE;  // By default, confirm everything.
  89.  
  90. int bDragLeftBtn = FALSE;  // By default, drag by right mouse button a la OS/2.
  91.  
  92. const int MAXDIRTEXT = 256;
  93. const int CYLBHEIGHT = 18;
  94.  
  95. const unsigned long CTRL_MOUSE_KEY = 1048576;  // (2^20)
  96.  
  97. char szINIPath[256];
  98.  
  99. typedef struct _TREEVIEW_ITEM
  100. {
  101.     int nListBoxIndex;  // Index # of this entry.
  102.     int nLevel;         // In hierarchical list, this is the level of this entry
  103.     int nExpandCode;    // 0 = Nothing to expand, 1 == Can Expand [+], 2 Already Expanded [-]
  104.     int bIsEndOfLevel;
  105.     LPSTR Parent; // Our parent's index on hierarchy, (NULL) for root entries
  106.     int iImage;
  107.     int iSelectedImage;
  108.     LPSTR lpszDirText;
  109.     int nTextLen;
  110. } TREEVIEW_ITEM;
  111.  
  112. void ToUpperCase(char *pszOut, char *pszIn, int nMaxLen)
  113. {
  114.     if(!pszOut || !pszIn)
  115.         return;
  116.  
  117.     for(int i = 0; i < strlen(pszIn) && i < nMaxLen; i++)
  118.         pszOut[i] = toupper(pszIn[i]);
  119.  
  120.     if(i < nMaxLen)
  121.         pszOut[i] = '\0';
  122. }
  123.  
  124. class DIRLIST_ITEM
  125. {
  126. public:
  127.     TREEVIEW_ITEM *pTVI;  // This is not allocated in this class!
  128.  
  129.     DIRLIST_ITEM(TREEVIEW_ITEM *pMyTVI = NULL) { pTVI = pMyTVI; }
  130.  
  131.     int operator<(const DIRLIST_ITEM& CompareItem) {
  132.         if(!pTVI && !CompareItem.pTVI)
  133.             return TRUE;
  134.         else if(!pTVI && CompareItem.pTVI)
  135.             return FALSE;
  136.         else if(pTVI && !CompareItem.pTVI)
  137.             return FALSE;
  138.         else // Two valid entries, compare strings--case insensitive here..
  139.         {
  140.             int rc = strcmpi(pTVI->lpszDirText, (char *)CompareItem.pTVI->lpszDirText);
  141.             if(rc < 0)
  142.                 return TRUE;
  143.             else
  144.                 return FALSE;
  145.         }
  146.     }
  147.     int operator==(const DIRLIST_ITEM& CompareItem) {
  148.         if(pTVI == CompareItem.pTVI)  // If data items are equal, we have a match.
  149.             return TRUE;
  150.         else
  151.             return FALSE;
  152.     }
  153. };
  154.  
  155. typedef TREEVIEW_ITEM *PTREEVIEW_ITEM;
  156.  
  157. class LBHITTEST
  158. {
  159. public:
  160.     int nIndex;
  161.     TRect rect;
  162.  
  163.     LBHITTEST(int nNewIndex, TRect& r) { nIndex = nNewIndex; rect = r; }
  164.  
  165.     int operator==(LBHITTEST& OldRec)
  166.     {
  167.         if(OldRec.nIndex == nIndex && OldRec.rect == rect)
  168.             return TRUE;
  169.         else
  170.             return FALSE;
  171.     }
  172. };
  173.  
  174. TIArrayAsVector <LBHITTEST> FolderDragTargets(16, 0, 1);
  175.  
  176. const char PRF_INI_FILENAME[] = "WARPCAB.INI";
  177. const char PRF_INI_SECTION[] = "filetypes";
  178.  
  179. typedef unsigned int uint;
  180.  
  181. const int MAXIMAGES = 11;
  182. const int CXIMAGE = 16;
  183. const int CYIMAGE = 16;
  184.  
  185. const int cxSplitterWidth = 8;
  186.  
  187. class CustomListBox : public TListBox
  188. {
  189. public:
  190.     HWND hwndParent;
  191.  
  192.     int bForwarding;
  193.  
  194.     CustomListBox(TWindow* parent, int id,
  195.                   int x, int y, int w, int h,
  196.                   TModule* module = 0) : TListBox(parent, id, x, y, w, h, module)
  197.                     {
  198.                         if(parent)
  199.                             hwndParent = parent->HWindow;
  200.                         else
  201.                             hwndParent = NULL;
  202.  
  203.                         bForwarding = FALSE;
  204.                     }
  205.  
  206.     void SetForwarding(BOOL bOn = TRUE) { bForwarding = bOn; }
  207.  
  208.  
  209.     BOOL EvSetCursor(HWND hwnd, uint hittest, uint mousemsg) { return TRUE; }
  210.  
  211.     void EvMouseMove(UINT keys, TPoint& point);
  212.  
  213.     // OS/2 drag and drop messages.
  214.     LRESULT DoDragOver(WPARAM wParam, LPARAM lParam) { return (LRESULT)WinSendMsg(hwndParent, DM_DRAGOVER, (MPARAM)wParam, (MPARAM)GetId()); }
  215.     LRESULT DoDragLeave(WPARAM wParam, LPARAM lParam) { return (LRESULT)WinSendMsg(hwndParent, DM_DRAGLEAVE, (MPARAM)wParam, (MPARAM)GetId()); }
  216.     LRESULT DoDropHelp(WPARAM wParam, LPARAM lParam) { return (LRESULT)WinSendMsg(hwndParent, DM_DROPHELP, (MPARAM)wParam, (MPARAM)GetId()); }
  217.     LRESULT DoDrop(WPARAM wParam, LPARAM lParam) { return (LRESULT)WinSendMsg(hwndParent, DM_DROP, (MPARAM)wParam, (MPARAM)GetId()); }
  218.  
  219.     DECLARE_RESPONSE_TABLE(CustomListBox);
  220. };
  221.  
  222. DEFINE_RESPONSE_TABLE1(CustomListBox, TListBox)
  223.     EV_WM_MOUSEMOVE,
  224.     EV_WM_SETCURSOR,
  225.     EV_MESSAGE(DM_DRAGOVER, DoDragOver),
  226.     EV_MESSAGE(DM_DRAGLEAVE, DoDragLeave),
  227.     EV_MESSAGE(DM_DROPHELP, DoDropHelp),
  228.     EV_MESSAGE(DM_DROP, DoDrop),
  229. END_RESPONSE_TABLE;
  230.  
  231. //    Define our Main Window.
  232. class DFrame : public TWindow
  233. {
  234.     public:
  235.         DFrame(TWindow *parent = NULL);
  236.         ~DFrame();
  237.         void SetupWindow();
  238.  
  239.         // Menu Commands
  240.         int nOpenFileIndex;
  241.  
  242.         void CmOpen();
  243.         void CmEnableOpen(TCommandEnabler& ce);
  244.  
  245.         void CmMove();
  246.         void CmEnableMove(TCommandEnabler& ce);
  247.  
  248.         void CmCopy();
  249.         void CmEnableCopy(TCommandEnabler& ce);
  250.  
  251.         void CmDelete();
  252.         void CmEnableDelete(TCommandEnabler& ce);
  253.  
  254.         void CmProperties();
  255.         void CmEnableProperties(TCommandEnabler& ce);
  256.  
  257.         void CmRun();
  258.  
  259.         void CmAssociate();
  260.  
  261.         void CmCreateDir();
  262.         void CmExit();
  263.  
  264.         void CmShowName();
  265.         void CmAllFileDetails();
  266.         void CmPartialFileDetails();
  267.  
  268.         void CmSelectFiles();
  269.         void CmSelectAll();
  270.         void CmSelectNone();
  271.  
  272.         void CmSortByName();
  273.         void CmSortByType();
  274.         void CmSortBySize();
  275.         void CmSortByDate();
  276.  
  277.         void CmRefreshOneFolder();
  278.         void CmRefreshAllFolders();
  279.  
  280.         void CmShowFileTypes();
  281.  
  282.         void CmConfirmOptions();
  283.  
  284.         void CmDragWithLeftBtn();
  285.  
  286.         void CmAbout();
  287.  
  288.         int bShowAllFileDetails;
  289.  
  290.         int bShowSize;
  291.         int bShowTimeStamp;
  292.         int bShowAttr;
  293.  
  294.         HWND hwndMenu;
  295.  
  296.         TMemoryDC *dcMem;
  297.  
  298.         // Sent by threads to report a result of a file operation.
  299.         LRESULT PMFileOperationResult(WPARAM wParam, LPARAM lParam);
  300.  
  301.         // Mouse and drag and drop messages.
  302.         void EvLButtonDown(UINT keys, TPoint& point);
  303.         void EvRButtonDown(UINT keys, TPoint& point);
  304.  
  305.         void EvMouseMove(UINT keys, TPoint& point);
  306.  
  307.         void EvLButtonUp(UINT keys, TPoint& point);
  308.         void EvRButtonUp(UINT keys, TPoint& point);
  309.  
  310.         // Owner-draw listbox support.
  311.         UINT EvMeasureItem(UINT ctrlId, UINT index) { return CYLBHEIGHT; }
  312.  
  313.         // Custom handler for WM_OWNERDRAW--The EvDrawItem() version is gutted and
  314.         // supports only a dummy OWNERITEM structure.
  315.         LRESULT DoDrawItem(WPARAM, LPARAM);
  316.         void DrawImage(TDC& dc, int nImage, int x, int y, UINT dwROP = SRCCOPY, BOOL bUseMask = FALSE);
  317.  
  318.         unsigned int wLastMouseMsg;
  319.         TPoint ptLastMouse;
  320.  
  321.         TRect rOldRect;
  322.  
  323.         HPOINTER hptrFile;
  324.         HPOINTER hptrFolder;
  325.         HPOINTER hptrMulti;
  326.         HPOINTER hptrBusy;
  327.  
  328.         void UpdateFileHdrText(LPSTR lpszNewText = NULL);
  329.         void Paint(TDC& dc, BOOL erase, TRect& rect);
  330.  
  331.         void EvSize(uint sizeType, TSize& size);
  332.  
  333.         void DrawSplitterWindowBar(TDC& dc, TRect& rect);
  334.  
  335.         // (Functions that pass important control items from frame...)
  336.         void SetStatusTextCtrl(TTextGadget *pMyStatusText) { pStatusText = pMyStatusText;
  337.                     pGlobalStatusBar = pMyStatusText; }
  338.         void SetFrame(TWindow *pMyFrame) { pFrame = pMyFrame; }
  339.  
  340.         int GetSelectedDir(string& strDir, int nTargetIndex = -1);
  341.         int GetFileListDblClickIndex();
  342.  
  343.         int bFolderOnlyNoSelections;
  344.  
  345.         void LoadInitDirs(void);
  346.  
  347.         BOOL IsNextNodeExpandable(LPSTR lpszThisDir);
  348.         BOOL ExpandDirNode(TREEVIEW_ITEM *Parent, int nStartIndex, int nLevel, LPSTR lpszThisDir, LPSTR lpszInitSearch);
  349.  
  350.         BOOL ResortFileEntries(int nNewSortMethod = SORT_BY_NAME);
  351.  
  352.         int GetFileSelections();
  353.         int nFileListSelCount;
  354.  
  355.         // Handle listbox notification commands for clicking and double-clicking.
  356.         void OnFolderListClick();
  357.         void OnFolderListDblClick();
  358.         void OnFileListClick();
  359.         void OnFileListDblClick();
  360.  
  361.         int cxMaxFileListHorizExt;
  362.  
  363.         // These fields are used to track how wide each element to display is.
  364.         int cxName;
  365.         int cxSize;
  366.         int cxTimeStamp;
  367.         int cxAttribute;
  368.  
  369.         BOOL bResizingPanes;
  370.         BOOL bOverResizer;
  371.  
  372.         TRect rFolderListHdr;
  373.         TRect rFileListHdr;
  374.  
  375.         CustomListBox *FolderList;
  376.         TRect rFolderList;
  377.  
  378.         TRect rSplitter;
  379.         TRect rOldSplitter;
  380.  
  381.         CustomListBox *FileList;
  382.         TRect rFileList;
  383.  
  384.         int cxWin;
  385.         int cyWin;
  386.  
  387.         int cyFolderList;
  388.         int cyFileList;
  389.  
  390.         int cxBorder;
  391.         int cyTitleBar;
  392.  
  393.         string strDirHdr;
  394.         string strFileHdr;
  395.         string strStatus;
  396.  
  397.         TFont *pfontWork;
  398.         TFont *pfontLB;
  399.  
  400.         TTextGadget *pStatusText;
  401.  
  402.         TWindow *pFrame;
  403.  
  404.         TPen *HighlightPen;
  405.  
  406.         TPen *ConnectorPen;
  407.         TPen *SolidConnectorPen;
  408.  
  409.         TBrush *MaskBrush;
  410.  
  411.         DWORD rgbLBBackground;
  412.  
  413.         // Used to track bitmaps/images in ownerdraw listboxes
  414.         TBitmap *ImageList[MAXIMAGES];
  415.  
  416.         char szCurrentListViewDir[256];
  417.         int nFileSourceCount;
  418.  
  419.         int nSortCode;
  420.         int nOldSortCheckedItem;
  421.  
  422.         // For dragging files.
  423.         int nTargetIndex;
  424.         int bDraggingFiles;
  425.         int bFirstDragMovement;
  426.  
  427.         int LoadDirectoryToFilesLB(TListBox *FileLB, LPSTR lpszDir, LPSTR lpszMask, int bShowHiddenSysFilesToo, int nSortCode = SORT_BY_NAME);
  428.  
  429.         int AddTreeViewItem(TListBox* pLB, TREEVIEW_ITEM& TreeViewItem, int nPos = -1);
  430.         int AddListViewItem(TListBox* pLB, FILEENTRY *ListViewItem, int nPos = -1);
  431.  
  432.         void ClearFolderList();
  433.         void ClearFileList();
  434.  
  435.         BOOL IsWindowIconic();
  436.  
  437.         long lCount;
  438.  
  439.         // Change the cursor.
  440.         void ShowArrowCursor() { SetCursor(0, IDC_ARROW); }
  441.         void ShowWaitCursor() { SetCursor(0, IDC_WAIT); }
  442.  
  443.         int cxCurrentDir; // Used to size current directory listbox;
  444.  
  445.         LRESULT DoDragOver(WPARAM wParam, LPARAM lParam);
  446.         LRESULT DoDragLeave(WPARAM wParam, LPARAM lParam);
  447.         LRESULT DoDropHelp(WPARAM wParam, LPARAM lParam);
  448.         LRESULT DoDrop(WPARAM wParam, LPARAM lParam);
  449.  
  450.         int nMouseBtnDownCode;
  451.         int bCouldDrag;
  452.  
  453.         int bLocalDragging;
  454.         int bRemoteDragging;
  455.         int bRemoteDraggingInit;
  456.  
  457.     DECLARE_RESPONSE_TABLE (DFrame);
  458. };
  459.  
  460. // The 'RESPONSE TABLE' here is a definition of what
  461. // 'events' or Windows messages our window is prepared to handle.
  462. DEFINE_RESPONSE_TABLE1(DFrame, TWindow)
  463.     EV_WM_SIZE,
  464.     EV_WM_LBUTTONDOWN,
  465.     EV_WM_MOUSEMOVE,
  466.     EV_WM_LBUTTONUP,
  467.     EV_WM_RBUTTONDOWN,
  468.     EV_WM_RBUTTONUP,
  469.     EV_WM_MEASUREITEM,
  470.     EV_MESSAGE(WM_DRAWITEM, DoDrawItem),
  471.     EV_CHILD_NOTIFY(IDC_DIRLIST, LBN_SELCHANGE, OnFolderListClick),
  472.     EV_CHILD_NOTIFY(IDC_DIRLIST, LBN_DBLCLK, OnFolderListDblClick),
  473.     EV_CHILD_NOTIFY(IDC_FILELIST, LBN_SELCHANGE, OnFileListClick),
  474.     EV_CHILD_NOTIFY(IDC_FILELIST, LBN_DBLCLK, OnFileListDblClick),
  475.     EV_COMMAND(CM_OPEN, CmOpen),
  476.     EV_COMMAND(CM_MOVE, CmMove),
  477.     EV_COMMAND(CM_COPY, CmCopy),
  478.     EV_COMMAND(CM_DELETE, CmDelete),
  479.     EV_COMMAND(CM_PROPERTIES, CmProperties),
  480.     EV_COMMAND(CM_RUN, CmRun),
  481.     EV_COMMAND(CM_ASSOCIATE, CmAssociate),
  482.     EV_COMMAND(CM_CREATE_DIR, CmCreateDir),
  483.     EV_COMMAND(CM_APP_EXIT, CmExit),
  484.     EV_COMMAND(CM_SELECTFILES, CmSelectFiles),
  485.     EV_COMMAND(CM_SELECTALL, CmSelectAll),
  486.     EV_COMMAND(CM_CLEARSELS, CmSelectNone),
  487.     EV_COMMAND(CM_FILE_NAME, CmShowName),
  488.     EV_COMMAND(CM_ALL_DETAILS, CmAllFileDetails),
  489.     EV_COMMAND(CM_PARTIAL_DETAILS, CmPartialFileDetails),
  490.     EV_COMMAND(CM_SHOWFILES, CmShowFileTypes),
  491.     EV_COMMAND(CM_SORTNAME, CmSortByName),
  492.     EV_COMMAND(CM_SORTTYPE, CmSortByType),
  493.     EV_COMMAND(CM_SORTSIZE, CmSortBySize),
  494.     EV_COMMAND(CM_SORTDATE,CmSortByDate),
  495.     EV_COMMAND(CM_CONFIRMATION, CmConfirmOptions),
  496.     EV_COMMAND(CM_REFRESH, CmRefreshOneFolder),
  497.     EV_COMMAND(CM_RELOAD_FOLDERS, CmRefreshAllFolders),
  498.     EV_COMMAND(CM_DRAG_LEFT_BTN, CmDragWithLeftBtn),
  499.     EV_COMMAND(CM_ABOUT, CmAbout),
  500.     EV_COMMAND_ENABLE(CM_OPEN, CmEnableOpen),
  501.     EV_COMMAND_ENABLE(CM_MOVE, CmEnableMove),
  502.     EV_COMMAND_ENABLE(CM_COPY, CmEnableCopy),
  503.     EV_COMMAND_ENABLE(CM_DELETE, CmEnableDelete),
  504.     EV_COMMAND_ENABLE(CM_PROPERTIES, CmEnableProperties),
  505.     EV_MESSAGE(DM_DRAGOVER, DoDragOver),
  506.     EV_MESSAGE(DM_DRAGLEAVE, DoDragLeave),
  507.     EV_MESSAGE(DM_DROPHELP, DoDropHelp),
  508.     EV_MESSAGE(DM_DROP, DoDrop),
  509. END_RESPONSE_TABLE;
  510.  
  511. // Class constructor.
  512. DFrame::DFrame(TWindow *parent)
  513. {
  514.     Init(parent, 0, 0);
  515.  
  516.     // Load bitmaps images.
  517.     HINSTANCE hInst = GetModule()->GetInstance();
  518.  
  519.     assert(hInst);
  520.  
  521.     dcMem = NULL;
  522.  
  523.     cxName = 0;
  524.     cxSize = 0;
  525.     cxTimeStamp = 0;
  526.     cxAttribute = 0;
  527.  
  528.     nMouseBtnDownCode = NO_BTN;
  529.     bCouldDrag = FALSE;
  530.  
  531.     bLocalDragging = FALSE;
  532.     bRemoteDragging = FALSE;
  533.     bRemoteDraggingInit = FALSE;
  534.  
  535.     ImageList[ID_FLOPPY] = new TBitmap(hInst, ID_FLOPPY);
  536.     ImageList[ID_HDD] = new TBitmap(hInst, ID_HDD);
  537.     ImageList[ID_CDROM] = new TBitmap(hInst, ID_CDROM);
  538.     ImageList[ID_FOLDER] = new TBitmap(hInst, ID_FOLDER);
  539.     ImageList[ID_OPEN_FOLDER] = new TBitmap(hInst, ID_OPEN_FOLDER);
  540.     ImageList[ID_DOCUMENT] = new TBitmap(hInst, ID_DOCUMENT);
  541.     ImageList[ID_EXE] = new TBitmap(hInst, ID_EXE);
  542.     ImageList[ID_CMD] = new TBitmap(hInst, ID_CMD);
  543.     ImageList[ID_BAT] = new TBitmap(hInst, ID_BAT);
  544.     ImageList[ID_COM] = new TBitmap(hInst, ID_COM);
  545.  
  546.     pfontWork = new TFont(
  547.          "Helv",                     // facename -- Available by default
  548.          -(cyTitleBar * 2) / 3,      // height,
  549.          0, 0, 0, FW_NORMAL,         // width, esc, orientation, weight
  550.          VARIABLE_PITCH | FF_SWISS,  // Pitch and Family
  551.          FALSE, FALSE, FALSE,        // Italic, Underline, Strikeout
  552.          ANSI_CHARSET,               // Charset
  553.          OUT_CHARACTER_PRECIS,       // Output precision
  554.          CLIP_DEFAULT_PRECIS,        // Clip precision
  555.          PROOF_QUALITY               // Quality
  556.       );
  557.  
  558.     pfontLB = new TFont(
  559.          "Helv",                     // facename -- Available by default
  560.          -8,                                 // height,
  561.          0, 0, 0, FW_NORMAL,         // width, esc, orientation, weight
  562.          VARIABLE_PITCH | FF_SWISS,  // Pitch and Family
  563.          FALSE, FALSE, FALSE,        // Italic, Underline, Strikeout
  564.          ANSI_CHARSET,               // Charset
  565.          OUT_CHARACTER_PRECIS,       // Output precision
  566.          CLIP_DEFAULT_PRECIS,        // Clip precision
  567.          PROOF_QUALITY               // Quality
  568.       );
  569.  
  570.     ConnectorPen = new TPen(TColor(128, 128, 128), 1, PS_DOT);
  571.     SolidConnectorPen = new TPen(TColor(128, 128, 128), 1, PS_SOLID);
  572.     MaskBrush = new TBrush(TColor(0, 0, 255));
  573.  
  574.     rgbLBBackground = WinQuerySysColor(HWND_DESKTOP,
  575.                                                   SYSCLR_ENTRYFIELD,
  576.                                                   0);
  577.     bShowAllFileDetails = TRUE;
  578.  
  579.     bShowTimeStamp = TRUE;
  580.     bShowAttr = TRUE;
  581.     bShowSize = TRUE;
  582.  
  583.     bDraggingFiles = FALSE;
  584.     bResizingPanes = FALSE;
  585.     bOverResizer = FALSE;
  586.  
  587.     FolderList = NULL;
  588.     FileList = NULL;
  589.  
  590.     ulShowAttrBits = 0;
  591.  
  592.     cxBorder = WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
  593.     cyTitleBar = WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR);
  594.  
  595.     strDirHdr = "All Folders";
  596.     strFileHdr = "";
  597.     strStatus = "No objects selected";
  598.  
  599.     bFolderOnlyNoSelections = FALSE;
  600.  
  601.     pStatusText = NULL;
  602.  
  603.     cxCurrentDir = 0;
  604.  
  605.     // Retrieve working directory of Warp Cabinet and construct .INI file
  606.     // path accordingly.
  607.     strcpy(szINIPath, "WARPCAB.INI");
  608.     ULONG DiskNum;
  609.     ULONG LogDisk;
  610.     int rc;
  611.  
  612.     BYTE szBuff[256];
  613.     ULONG cbBytes = 256;
  614.     rc = DosQueryCurrentDisk(&DiskNum, &LogDisk);
  615.     if(rc == 0)
  616.     {
  617.         rc = DosQueryCurrentDir(DiskNum,
  618.                                         szBuff,
  619.                                         &cbBytes);
  620.         if(rc == 0)
  621.         {
  622.             szINIPath[0] = DiskNum + 'A' - 1;
  623.             szINIPath[1] = ':';
  624.             szINIPath[2] = '\\';
  625.             szINIPath[3] = 0;
  626.             strcat(szINIPath, szBuff);
  627.             strcat(szINIPath, "\\WARPCAB.INI");
  628.         }
  629.     }
  630.  
  631.     FILEASSOCIATION *pNewFileAssoc = NULL;
  632.  
  633.     nTargetIndex = -1;
  634.  
  635.     // .INI file is WARPCAB.INI
  636.     int nCount = 1;
  637.     while(1)
  638.     {
  639.         pNewFileAssoc = new FILEASSOCIATION;
  640.         if(!pNewFileAssoc)
  641.         {
  642.             MessageBox("Can't load file associations.", "Not Enough Memory", MB_ICONSTOP);
  643.             break;
  644.         }
  645.         rc = pNewFileAssoc->LoadFromProfileFile(HWindow, szINIPath, (LPSTR)PRF_INI_SECTION, nCount);
  646.  
  647.         if(!rc)   // Break on first fail!
  648.             break;
  649.  
  650.         // Add to our array...
  651.         FileAssociations.Add(pNewFileAssoc);
  652.         nCount++;
  653.     }
  654.  
  655.     strcpy(szMask, "*.*");
  656.     strcpy (szSelByMask, "*.*");
  657.  
  658.     nSortCode = SORT_BY_NAME;
  659.     nOldSortCheckedItem = CM_SORTNAME;
  660.  
  661.     hwndMenu = NULL;
  662.  
  663.     pFrame = NULL;
  664.  
  665.     strcpy(szCurrentListViewDir, "");
  666.     nFileListSelCount = 0;
  667.  
  668.     cxMaxFileListHorizExt = 0;
  669.  
  670.     bDraggingFiles = FALSE;
  671.     bFirstDragMovement = FALSE;
  672.  
  673.     bDragCopy = FALSE; // The default here.
  674.  
  675.     wLastMouseMsg = -1;
  676.     ptLastMouse.x = -1;
  677.     ptLastMouse.y = -1;
  678.  
  679.     HighlightPen = new TPen(TColor(0,0,0), 2, PS_DOT);
  680.  
  681.     rOldRect.Set(-1,-1,-1,-1);
  682.  
  683.     hptrFile   = WinQuerySysPointer (HWND_DESKTOP, SPTR_FILE, FALSE);
  684.     hptrFolder = WinQuerySysPointer (HWND_DESKTOP, SPTR_FOLDER, FALSE);
  685.     hptrMulti  = WinQuerySysPointer (HWND_DESKTOP, SPTR_MULTFILE, FALSE);
  686.  
  687.     pGlobalParent = this;
  688.     hwndGlobalParent = HWindow;
  689.  
  690.     nOpenFileIndex = -1;
  691. }
  692.  
  693. DFrame::~DFrame()
  694. {
  695.     ClearFolderList();
  696.     delete FolderList;
  697.  
  698.     ClearFileList();
  699.     delete FileList;
  700.  
  701.     if(dcMem)
  702.     {
  703.         // Clean-up our memory DC.
  704.         dcMem->RestoreObjects();
  705.         delete dcMem;
  706.     }
  707.  
  708.     if(pfontWork)
  709.         delete pfontWork;
  710.  
  711.     if(pfontLB)
  712.         delete pfontLB;
  713.  
  714.     // Clean-up images.
  715.     delete ImageList[ID_FLOPPY];
  716.     delete ImageList[ID_HDD];
  717.     delete ImageList[ID_CDROM];
  718.     delete ImageList[ID_FOLDER];
  719.     delete ImageList[ID_OPEN_FOLDER];
  720.     delete ImageList[ID_DOCUMENT];
  721.     delete ImageList[ID_EXE];
  722.     delete ImageList[ID_CMD];
  723.     delete ImageList[ID_BAT];
  724.     delete ImageList[ID_COM];
  725.  
  726.     // Clean-up drawing tools.
  727.     delete ConnectorPen;
  728.  
  729.     delete SolidConnectorPen;
  730.  
  731.     delete MaskBrush;
  732.  
  733.     delete HighlightPen;
  734.  
  735.     WinDestroyPointer(hptrFile);
  736.     WinDestroyPointer(hptrFolder);
  737.     WinDestroyPointer(hptrMulti);
  738.     WinDestroyPointer(hptrBusy);
  739.  
  740.     CleanupArrays();
  741.  
  742.     FolderDragTargets.Flush(TShouldDelete::Delete);
  743.  
  744.     int rc;
  745.     int bError = FALSE;
  746.  
  747.     // Save association array and then clean-it up.
  748.     int nCount = 1;
  749.  
  750.     unlink((LPSTR)szINIPath);
  751.  
  752.     for(int i = 0; i < FileAssociations.GetItemsInContainer(); i++)
  753.     {
  754.         FILEASSOCIATION *pFileAssoc = FileAssociations[i];
  755.         if(pFileAssoc)
  756.         {
  757.             rc = pFileAssoc->SaveToProfileFile(HWindow, (LPSTR)szINIPath, (LPSTR)PRF_INI_SECTION, nCount);
  758.             if(!rc)
  759.                 bError = TRUE;
  760.         }
  761.         else
  762.             bError = TRUE;
  763.  
  764.         if(bError)
  765.         {
  766.             MessageBox("Can't save file types to .INI file.  Associations may be lost.", "Can't Save File", MB_ICONSTOP);
  767.             break;
  768.         }
  769.         // Otherwise, go to next type.
  770.         nCount++;
  771.     }
  772.     // Flush and kill off records inside array.
  773.     FileAssociations.Flush(TShouldDelete::Delete);
  774. }
  775.  
  776. void DFrame::ClearFolderList()
  777. {
  778.     int nItems = FolderList->GetCount();
  779.  
  780.     TREEVIEW_ITEM *tvi;
  781.  
  782.     for(int i = 0; i < nItems; i++)
  783.     {
  784.         tvi = (TREEVIEW_ITEM *)FolderList->GetItemData(i);
  785.         if(tvi)
  786.         {
  787.             if(tvi->lpszDirText)
  788.                 delete[] tvi->lpszDirText;
  789.             delete tvi;
  790.         }
  791.     }
  792.     FolderList->ClearList();
  793. }
  794.  
  795. void DFrame::ClearFileList()
  796. {
  797.     int nItems = FileList->GetCount();
  798.  
  799.     FILEENTRY *lvi;
  800.  
  801.     for(int i = 0; i < nItems; i++)
  802.     {
  803.         lvi = (FILEENTRY *)FileList->GetItemData(i);
  804.         if(lvi)
  805.             delete lvi;
  806.     }
  807.  
  808.     cxMaxFileListHorizExt = 0;
  809.  
  810.     FileList->ClearList();
  811. }
  812.  
  813. BOOL DFrame::IsNextNodeExpandable(LPSTR lpszThisDir)
  814. {
  815.     struct ffblk FileInfo;
  816.  
  817.     char szBaseDir[256]; // Final '\\' not used.
  818.     char szNewDir[256];
  819.     char szInitSearch[256];
  820.  
  821.     strcpy(szBaseDir, lpszThisDir);
  822.  
  823.     strcpy(szInitSearch, szBaseDir);
  824.     strcat(szInitSearch, "\\*.*");
  825.  
  826.     unsigned long ulShowBits = FA_DIREC | ulShowAttrBits;
  827.  
  828.     int rc;
  829.  
  830.     int bFirstTime = TRUE;
  831.  
  832.     // Check for a sub-directory in this directory.
  833.     // If we have one, we're expandable.
  834.     while(1)
  835.     {
  836.         if(bFirstTime)
  837.         {
  838.             rc = findfirst((LPSTR)szInitSearch, &FileInfo, FA_DIREC);
  839.             bFirstTime = FALSE;
  840.         }
  841.         else
  842.             rc = findnext(&FileInfo);
  843.         if(rc)
  844.             return FALSE;  // No sub-dirs found.
  845.  
  846.         if((ulShowBits & FileInfo.ff_attrib) == ulShowBits && FileInfo.ff_name[0] != '.')
  847.             return TRUE; // Then a valid sub-dir.  We're expandable!
  848.     }
  849. }
  850.  
  851. BOOL DFrame::ResortFileEntries(int nNewSortMethod)
  852. {
  853.     int nCount = FileList->GetCount();
  854.  
  855.     if(nNewSortMethod    == nSortCode || nCount < 2)
  856.         return TRUE;  // Already done.
  857.  
  858.     // Add FileEntry records back into array to sort them.
  859.     TISArrayAsVector <FILEENTRY> FileEntries(10, 0, 1);
  860.  
  861.     FILEENTRY *pThisFileEntry;
  862.  
  863.     ShowWaitCursor();
  864.  
  865.     FileList->SetRedraw(FALSE);
  866.  
  867.     FILEENTRY *lvi;
  868.  
  869.     for(int i = 0; i < nCount; i++)
  870.     {
  871.         lvi = (FILEENTRY *)FileList->GetItemData(i);
  872.         if(lvi)
  873.         {
  874.             lvi->nSortMethod = nNewSortMethod;
  875.             FileEntries.Add(lvi);
  876.         }
  877.     }
  878.     FileList->ClearList();
  879.  
  880.     for(i = 0; i < FileEntries.GetItemsInContainer(); i++)
  881.     {
  882.         pThisFileEntry = FileEntries[i];
  883.         AddListViewItem(FileList, pThisFileEntry);
  884.     }
  885.  
  886.     FileList->SetRedraw(TRUE);
  887.     ShowArrowCursor();
  888.     return TRUE;
  889. }
  890.  
  891. BOOL DFrame::ExpandDirNode(TREEVIEW_ITEM *Parent, int nStartIndex, int nLevel, LPSTR lpszThisDir, LPSTR lpszInitSearch)
  892. {
  893.     int bFirstTime = TRUE;
  894.     int bCanExpand;
  895.  
  896.     TREEVIEW_ITEM tvi;
  897.  
  898.     // Use an array of pointers to dir, list items--this is needed to sort items alphabetically here.
  899.     // (Fortunately, for directories, we can always just sort by folder name.
  900.     TISArrayAsVector <string> DirectorySorter (10,0,1);
  901.  
  902.     int rc;
  903.     int i;
  904.  
  905.     int nCount = 0;
  906.  
  907.     int nCurrentLBIndex = nStartIndex;
  908.  
  909.     struct ffblk FileInfo;
  910.  
  911.     char szBaseDir[256]; // Final '\\' not used.
  912.     char szNewDir[256];
  913.     char szInitSearch[256];
  914.  
  915.     unsigned long ulShowBits = FA_DIREC | ulShowAttrBits;
  916.  
  917.     strcpy((LPSTR)szBaseDir, lpszThisDir);
  918.  
  919.     strcpy((LPSTR)szInitSearch, szBaseDir);
  920.     strcat(szInitSearch, "\\");
  921.     // No backslash here.
  922.     strcat(szInitSearch, lpszInitSearch);
  923.  
  924.     bFirstTime = TRUE;
  925.  
  926.     int nLastAddIndex = -1;
  927.  
  928.     while(1)
  929.     {
  930.         if(bFirstTime)
  931.         {
  932.             rc = findfirst((LPSTR)szInitSearch, &FileInfo, FA_DIREC);
  933.             bFirstTime = FALSE;
  934.         }
  935.         else
  936.             rc = findnext(&FileInfo);
  937.         if(rc)
  938.             break; // We're done.
  939.  
  940.         if((ulShowBits & FileInfo.ff_attrib) == ulShowBits && FileInfo.ff_name[0] != '.')
  941.         {
  942.             string *pNewStr = new string(FileInfo.ff_name);
  943.             pNewStr->set_case_sensitive(0);
  944.             DirectorySorter.Add(pNewStr);
  945.         }
  946.     }
  947.  
  948.     // To here we should have an array of sorted directory strings.
  949.     string *pStr;
  950.  
  951.     nCount = DirectorySorter.GetItemsInContainer();
  952.     for(i = 0; i < nCount; i++)
  953.     {
  954.         pStr = DirectorySorter[i];
  955.  
  956.         if(!pStr)
  957.             continue;
  958.  
  959.         strcpy(szNewDir, szBaseDir);
  960.         strcat(szNewDir, "\\");
  961.         strcat(szNewDir, pStr->c_str());
  962.  
  963.         // To here, insert new node at provided point in listbox.
  964.         memset(&tvi, 0, sizeof(tvi));
  965.  
  966.         tvi.nListBoxIndex = nCurrentLBIndex + 1;  // Index # of this entry.
  967.         tvi.nLevel = nLevel;         // In hierarchical list, this is the level of this entry
  968.         bCanExpand = IsNextNodeExpandable(szNewDir);
  969.         if(bCanExpand)
  970.             tvi.nExpandCode = 1;
  971.         else
  972.             tvi.nExpandCode = 0;
  973.  
  974.         tvi.bIsEndOfLevel = FALSE;
  975.         tvi.Parent = (LPSTR)Parent;
  976.         tvi.iImage = ID_FOLDER;
  977.         tvi.iSelectedImage = ID_OPEN_FOLDER;
  978.         int len = pStr->length();
  979.         if(len == 0)
  980.             tvi.lpszDirText = NULL;
  981.         else
  982.         {
  983.             tvi.lpszDirText = new char[len + 1];
  984.             if(tvi.lpszDirText)
  985.             {
  986.                 strcpy(tvi.lpszDirText, pStr->c_str());
  987.                 tvi.nTextLen = len;
  988.             }
  989.         }
  990.  
  991.         nCurrentLBIndex = AddTreeViewItem(FolderList, tvi, nCurrentLBIndex);
  992.  
  993.         if(nCurrentLBIndex > -1)
  994.             nLastAddIndex = nCurrentLBIndex;
  995.         nCurrentLBIndex++;
  996.     }
  997.  
  998.     if(nLastAddIndex != -1)
  999.     {
  1000.         // Then mark last node in this directory as 'last'.
  1001.         TREEVIEW_ITEM *ptvi = (TREEVIEW_ITEM *)FolderList->GetItemData(nLastAddIndex);
  1002.         if(ptvi)
  1003.             ptvi->bIsEndOfLevel = TRUE;
  1004.     }
  1005.     DirectorySorter.Flush(TShouldDelete::Delete);
  1006.     return TRUE;
  1007. }
  1008.  
  1009. int DFrame::GetSelectedDir(string& strDir, int nTargetIndex)
  1010. {
  1011.     // Fills a passed string with a complete path (no final '\') of selected directory.
  1012.     strDir = "";
  1013.  
  1014.     string strThisSubDir("");
  1015.     string strSlash ="\\";
  1016.     string strPath("");
  1017.  
  1018.     int nIndex;
  1019.  
  1020.     if(nTargetIndex == -1)
  1021.         nIndex = FolderList->GetSelIndex();
  1022.     else
  1023.     {
  1024.         if(nTargetIndex > FolderList->GetCount() - 1)
  1025.             return FALSE;
  1026.         nIndex = nTargetIndex;
  1027.     }
  1028.     if(nIndex < 0)
  1029.         return FALSE;
  1030.  
  1031.     TREEVIEW_ITEM *tviThis = (TREEVIEW_ITEM *)FolderList->GetItemData(nIndex);
  1032.  
  1033.     while(1)
  1034.     {
  1035.         if(!tviThis)
  1036.             break;
  1037.  
  1038.         strThisSubDir = tviThis->lpszDirText;
  1039.  
  1040.         if(strPath.length() == 0)
  1041.             strPath = strThisSubDir;
  1042.         else
  1043.             strPath = strThisSubDir + strSlash + strPath;
  1044.  
  1045.         tviThis = (TREEVIEW_ITEM *)tviThis->Parent;
  1046.     }
  1047.  
  1048.     if(strPath.length() > 0)
  1049.     {
  1050.         strDir = strPath;
  1051.         return TRUE;
  1052.     }
  1053.     else
  1054.         return FALSE;
  1055. }
  1056.  
  1057. void DFrame::OnFolderListClick()
  1058. {
  1059.     // Retrieve current directory.
  1060.     string strDir;
  1061.     string strNew;
  1062.  
  1063.     ClearFileList();
  1064.  
  1065.     int rc = GetSelectedDir(strDir);
  1066.     if(!rc)
  1067.         return;
  1068.  
  1069.     ShowWaitCursor();
  1070.  
  1071.     rc = LoadDirectoryToFilesLB(FileList, (LPSTR)strDir.c_str(), szMask, bShowHiddenOrSysObjs, nSortCode);
  1072.  
  1073.     // Set new prompt info.
  1074.     if(rc)
  1075.     {
  1076.         strNew ="Contents of '";
  1077.         strNew += szCurrentListViewDir;
  1078.         strNew += "'";
  1079.     }
  1080.     else
  1081.         strNew = "Documents:";
  1082.  
  1083.     UpdateFileHdrText((LPSTR)strNew.c_str());
  1084.  
  1085.     FileList->SetTopIndex(0);
  1086.  
  1087.     // Force a repaint.
  1088.     TRect rActualFileList = FileList->GetClientRect();
  1089.     FileList->InvalidateRect(rActualFileList);
  1090.  
  1091.     if(FileList->GetCount() == 0)
  1092.         bFolderOnlyNoSelections = TRUE;
  1093.     else
  1094.         bFolderOnlyNoSelections = FALSE;
  1095.  
  1096.     ShowArrowCursor();
  1097. }
  1098.  
  1099. int DFrame::LoadDirectoryToFilesLB(TListBox *FileLB, LPSTR lpszDir, LPSTR lpszMask, int bShowHiddenSysFilesToo, int nSortCode)
  1100. {
  1101.     // Loads contents of specified directory to listbox.
  1102.     // Includes support for different sort options and which attributes to show.
  1103.     BOOL bFirstTime;
  1104.     struct ffblk FileInfo;
  1105.     int i, rc;
  1106.  
  1107.     // Arrays to hold directories and files in this directory.
  1108.     TISArrayAsVector <FILEENTRY> FileEntries(10, 0, 1);
  1109.  
  1110.     // Build search directory.
  1111.     string strSearchDir = lpszDir;
  1112.     strSearchDir += "\\*.*";
  1113.  
  1114.     unsigned long ulSearchBits;
  1115.     if(bShowHiddenSysFilesToo)
  1116.         ulSearchBits = FA_SYSTEM | FA_HIDDEN;
  1117.     else
  1118.         ulSearchBits = 0;
  1119.  
  1120.     // Hunt down all directories and files that match selected attributes.
  1121.     bFirstTime = TRUE;
  1122.     while(1)
  1123.     {
  1124.         if(bFirstTime)
  1125.         {
  1126.             rc = findfirst(strSearchDir.c_str(), &FileInfo, FA_DIREC | ulSearchBits);
  1127.             bFirstTime = FALSE;
  1128.         }
  1129.         else
  1130.             rc = findnext(&FileInfo);
  1131.         if(rc)
  1132.             break;  // We're finished
  1133.  
  1134.         // Otherwise we might have a match.
  1135.         // Check to see if it's a directory and if so, make sure that
  1136.         // if it's hidden, system, these bits are selected as well.
  1137.         if((FileInfo.ff_attrib & FA_DIREC) == FA_DIREC && (FileInfo.ff_name[0] != '.'))
  1138.         {
  1139.             // To here, add this directory name to our array.
  1140.             FileEntries.Add(new FILEENTRY(FileInfo, TRUE, nSortCode));
  1141.         }
  1142.     }
  1143.  
  1144.     bFirstTime = TRUE;
  1145.     strSearchDir = lpszDir;
  1146.     strSearchDir += "\\";
  1147.     strSearchDir += lpszMask;
  1148.  
  1149.     while(1)
  1150.     {
  1151.         if(bFirstTime)
  1152.         {
  1153.             rc = findfirst(strSearchDir.c_str(), &FileInfo, ulSearchBits);
  1154.             bFirstTime = FALSE;
  1155.         }
  1156.         else
  1157.             rc = findnext(&FileInfo);
  1158.         if(rc)
  1159.             break;  // We're finished
  1160.  
  1161.         // Otherwise we might have a match.
  1162.         // Check to see if it's a directory.  If not, make sure that
  1163.         // if its hidden, system or read-only, these bits are selected as well.
  1164.         if((FileInfo.ff_attrib & FA_DIREC) == FA_DIREC)
  1165.             continue;
  1166.         // To here, add this file information to our array.
  1167.         // This will be automatically sorted!
  1168.         FileEntries.Add(new FILEENTRY(FileInfo, FALSE, nSortCode));
  1169.     }
  1170.  
  1171.     // Now we have array of directories and files.
  1172.     // Add them to our list box.
  1173.     string strEntry;
  1174.     string strDir;
  1175.  
  1176.     FileLB->SetRedraw(FALSE);
  1177.     for(i = 0; i < FileEntries.GetItemsInContainer(); i++)
  1178.     {
  1179.         FILEENTRY *pThisFileEntry = FileEntries[i];
  1180.         rc = AddListViewItem(FileList, pThisFileEntry);
  1181.     }
  1182.  
  1183.     FileLB->SetRedraw(TRUE);
  1184.  
  1185.     // Clear arrays
  1186.     FileEntries.Flush(TShouldDelete::NoDelete);  // These file entries are attached
  1187.                                                                 // to our listbox.
  1188.     strcpy(szCurrentListViewDir, lpszDir);
  1189.     strStatus = "No objects selected";
  1190.     if(pStatusText)
  1191.     {
  1192.         pStatusText->SetText(strStatus.c_str());
  1193.     }
  1194.     return TRUE;
  1195. }
  1196.  
  1197. void DFrame::OnFolderListDblClick()
  1198. {
  1199.     // Process double-click -- Used to expand and collapse nodes in hierarchichal
  1200.     // sub-directory list.
  1201.     string strNewPath;
  1202.     string strBackslash("\\");
  1203.     string strThisToken;
  1204.  
  1205.     int nIndex;
  1206.  
  1207.     TREEVIEW_ITEM *tvi;
  1208.     TREEVIEW_ITEM *tviSearch = NULL;
  1209.  
  1210.     nIndex = FolderList->GetSelIndex();
  1211.  
  1212.     if(nIndex < 0)
  1213.         return; // Nothing selected.
  1214.  
  1215.     tvi = (TREEVIEW_ITEM *)FolderList->GetItemData(nIndex);
  1216.     if(!tvi)
  1217.     {
  1218.         MessageBox("Bad tree view data.", "Tree View Error", MB_ICONSTOP);
  1219.         return;
  1220.     }
  1221.  
  1222.     ShowWaitCursor();
  1223.     if(tvi->nExpandCode == 1)    // Expand this level.
  1224.     {
  1225.         strNewPath = "";
  1226.         tviSearch = tvi;
  1227.         while(1)
  1228.         {
  1229.             if(tviSearch)
  1230.             {
  1231.                 // Build this path...
  1232.                 strThisToken = tviSearch->lpszDirText;
  1233.                 if(strThisToken.length())
  1234.                 {
  1235.                     // Note path is built backwards, working up the tree to root!
  1236.                     if(strNewPath.length() > 0)
  1237.                         strNewPath = strThisToken + strBackslash + strNewPath;
  1238.                     else
  1239.                         strNewPath = strThisToken;  // First time, no backslash.
  1240.                 }
  1241.                 else
  1242.                     break;
  1243.             }
  1244.             else
  1245.                 break;
  1246.             if(tviSearch->Parent)  // Work our way up to root of hierarchical list.
  1247.             {
  1248.                 tviSearch = (TREEVIEW_ITEM *)tviSearch->Parent;
  1249.             }
  1250.             else
  1251.                 break;
  1252.         }
  1253.         if(strNewPath.length() == 0)
  1254.         {
  1255.             // Can't retrieve path.
  1256.             ShowArrowCursor();
  1257.             return;
  1258.         }
  1259.         // Otherwise, go ahead and load these entries.
  1260.         FolderList->ShowWindow(SW_HIDE);
  1261.         ExpandDirNode(tvi, nIndex + 1, tvi->nLevel + 1, (LPSTR)strNewPath.c_str(), "*.*");
  1262.  
  1263.         tvi->nExpandCode = 2; // Mark this entry as expanded.
  1264.  
  1265.         FolderList->Invalidate();
  1266.         FolderList->ShowWindow(SW_SHOWNORMAL);
  1267.     }
  1268.     else if(tvi->nExpandCode == 2)    // Collapse this level.
  1269.     {
  1270.         int nNext = nIndex + 1;
  1271.         int nTargetLevel = tvi->nLevel;
  1272.         int bLastOne;
  1273.  
  1274.         FolderList->ShowWindow(SW_HIDE);
  1275.         tviSearch = (TREEVIEW_ITEM *)FolderList->GetItemData(nNext);
  1276.         if(!tviSearch)
  1277.         {
  1278.             ShowArrowCursor();
  1279.             return;
  1280.         }
  1281.  
  1282.         while(1)
  1283.         {
  1284.             if(!tviSearch)
  1285.                 break;
  1286.  
  1287.             FolderList->DeleteString(nNext);
  1288.  
  1289.             if(tviSearch->lpszDirText)
  1290.                 delete[] tviSearch->lpszDirText;
  1291.             delete tviSearch;
  1292.  
  1293.             tviSearch = (TREEVIEW_ITEM *)FolderList->GetItemData(nNext);
  1294.  
  1295.             if(!tviSearch || tviSearch->nLevel <= nTargetLevel)
  1296.                 break;
  1297.         }
  1298.         tvi->nExpandCode = 1; // Mark this entry as expandable.
  1299.  
  1300.         FolderList->Invalidate();
  1301.         FolderList->ShowWindow(SW_SHOWNORMAL);
  1302.     }
  1303.     if(nIndex < FolderList->GetCount())
  1304.         FolderList->SetSelIndex(nIndex);
  1305.     nFileListSelCount = 0;
  1306.     ShowArrowCursor();
  1307. }
  1308.  
  1309. const int MAXENTRIES = 2049;  // 2 KB of selections.
  1310.  
  1311. void DFrame::OnFileListClick()
  1312. {
  1313.     ULONG ulTotalBytes = 0;   // 4GB max should do it.
  1314.     ULONG ulTotalKB;
  1315.  
  1316.     FILEENTRY *lvi;
  1317.  
  1318.     if(!pStatusText)  // Must have a status bar to set!!!
  1319.         return;
  1320.  
  1321.     strStatus = "";
  1322.  
  1323.     // On each click, update total dir.'s and files in status bar.
  1324.     int anSelIndexes[MAXENTRIES];
  1325.  
  1326.     nFileListSelCount = FileList->GetSelIndexes(anSelIndexes, MAXENTRIES);
  1327.  
  1328.     for(int i = 0; i < nFileListSelCount; i++)
  1329.     {
  1330.         lvi = (FILEENTRY *)FileList->GetItemData(anSelIndexes[i]);
  1331.         // Total up our selected files.
  1332.         if(lvi)
  1333.             ulTotalBytes += (ULONG)lvi->lFileSize;
  1334.     }
  1335.  
  1336.     if(nFileListSelCount == 0)
  1337.     {
  1338.         strStatus = "No objects selected";
  1339.     }
  1340.     else
  1341.     {
  1342.         char szTemp[40];
  1343.         if(nFileListSelCount == 1)
  1344.             strStatus = "1 object selected -- ";
  1345.         else
  1346.         {
  1347.             strStatus = itoa(nFileListSelCount, szTemp, 10);
  1348.             strStatus += " objects selected -- ";
  1349.         }
  1350.         ulTotalKB = ulTotalBytes / 1000;
  1351.         ltoa(ulTotalKB, szTemp, 10);
  1352.  
  1353.         strStatus += szTemp;
  1354.         strStatus += " KB";
  1355.     }
  1356.     pStatusText->SetText(strStatus.c_str());
  1357. }
  1358.  
  1359. void DFrame::OnFileListDblClick()
  1360. {
  1361.     char szCmdLine[256];
  1362.     char szNewCmdLine[256];
  1363.     char szParam[256];
  1364.  
  1365.     char szErrorInfo[256];
  1366.     RESULTCODES ReturnCodes;
  1367.     char szArgs[256];
  1368.     int bHasArgs = FALSE;
  1369.  
  1370.     int rc;
  1371.  
  1372.     static FILEENTRY *lvi;
  1373.  
  1374.     // Check for .EXE file or related file.
  1375.     int n;
  1376.     if(nOpenFileIndex != -1)
  1377.         n = nOpenFileIndex;
  1378.     else
  1379.         n = GetFileListDblClickIndex();  // Important! For multiple-selection listboxes.
  1380.     if(n < 0)
  1381.         return;
  1382.     else
  1383.     {
  1384.         lvi = (FILEENTRY *)FileList->GetItemData(n);
  1385.         if(!lvi)
  1386.             return;
  1387.     }
  1388.  
  1389.     if(lvi->nType == 1)
  1390.     {
  1391.         // It's a directory--change our open folder to this one.
  1392.         int nFolderIndex = FolderList->GetSelIndex();
  1393.         int nTargetLevel = -1;
  1394.         if(nFolderIndex < 0)
  1395.             return;  // Unexpected
  1396.         TREEVIEW_ITEM *tvi = (TREEVIEW_ITEM *)FolderList->GetItemData(nFolderIndex);
  1397.  
  1398.         if(tvi->nExpandCode == 1)
  1399.             OnFolderListDblClick();
  1400.  
  1401.         // Only folder name.
  1402.         string strTarget = lvi->szFileName;
  1403.  
  1404.         for(int i = nFolderIndex + 1; i <= FolderList->GetCount() - 1; i++)
  1405.         {
  1406.             tvi = (TREEVIEW_ITEM *)FolderList->GetItemData(i);
  1407.             if(!tvi || !tvi->lpszDirText)
  1408.                 continue;
  1409.             if(nTargetLevel == -1)
  1410.                 // If first time through, save our level in tree.
  1411.                 nTargetLevel = tvi->nLevel;
  1412.             else if(nTargetLevel != tvi->nLevel)
  1413.                 // If level has changed, we didn't find what we need.
  1414.                 break;
  1415.             if(strcmpi(tvi->lpszDirText, (LPSTR)strTarget.c_str()) == 0)
  1416.             {
  1417.                 // A match!
  1418.                 FolderList->SetSelIndex(i);
  1419.                 break;
  1420.             }
  1421.         }
  1422.         return;
  1423.     }
  1424.     else if(lvi->nType != 6)
  1425.     {
  1426.         if(nFileListSelCount > 1)
  1427.             return;
  1428.  
  1429.         // Then it's a runnable .EXE/.CMD/.BAT/.COM file...
  1430.         if(lvi->nType == 2 || lvi->nType == 5)
  1431.         {
  1432.             // An .EXE or .COM file -- just run this file.
  1433.             strcpy(szCmdLine, szCurrentListViewDir);
  1434.             strcat(szCmdLine, "\\");
  1435.             strcat(szCmdLine, lvi->szFileName);
  1436.         }
  1437.         else if(lvi->nType == 3)
  1438.         {
  1439.             // A .CMD file -- run with CMD.EXE
  1440.             strcpy(szCmdLine, "CMD.EXE");
  1441.  
  1442.             strcpy(szArgs, "/K ");
  1443.             strcat(szArgs, szCurrentListViewDir);
  1444.             strcat(szArgs, "\\");
  1445.             strcat(szArgs, lvi->szFileName);
  1446.  
  1447.             bHasArgs = TRUE;
  1448.         }
  1449.         else if(lvi->nType == 4)
  1450.         {
  1451.             // A BAT file -- run with COMMAND.COM
  1452.             strcpy(szCmdLine, "COMMAND.COM");
  1453.  
  1454.             strcpy(szArgs, szCurrentListViewDir);
  1455.             strcat(szArgs, "\\");
  1456.             strcat(szArgs, lvi->szFileName);
  1457.  
  1458.             bHasArgs = TRUE;
  1459.         }
  1460.         else
  1461.         {
  1462.             return;  // Undefined.
  1463.         }
  1464.         rc = RunProgramWithArgs(szCmdLine,
  1465.                                         bHasArgs ? szArgs : NULL);
  1466.  
  1467.         if(!rc)
  1468.         {
  1469.             if(lvi->nType == 2)
  1470.             {
  1471.                 // Allow Windows 3.1 .EXE's to run too...
  1472.                 rc = MessageBox("Can't run this program as a DOS or OS/2 executable.  Try to run as a WIN-OS/2 application instead?.", "Can't Run", MB_ICONQUESTION | MB_YESNOCANCEL);
  1473.                 if(rc == IDYES)
  1474.                 {
  1475.                     strcpy(szArgs, "/K progman.exe ");
  1476.                     strcat(szArgs, szCmdLine);
  1477.  
  1478.                     rc = RunProgramWithArgs("CMD.EXE", szArgs);
  1479.                     if(!rc)
  1480.                         MessageBox("There was an error running this program.  Check that path is correct or close some programs to free up memory and try again.", "Can't Run", MB_ICONSTOP);
  1481.                 }
  1482.             }
  1483.             else
  1484.                 MessageBox("There was an error running this program.  Check that path is correct or close some programs to free up memory and try again.", "Can't Run", MB_ICONSTOP);
  1485.  
  1486.         }
  1487.         return;
  1488.     }
  1489.     else
  1490.     {
  1491.         // Then it's a document (== 6)--Run it using the list of associations.
  1492.         if(nFileListSelCount > 1)
  1493.             return;
  1494.  
  1495.         FILEASSOCIATION *pThisFileAssoc = FileAssociations.FirstThat(FindFileAssociation, lvi->szExt);
  1496.  
  1497.         if(!pThisFileAssoc)
  1498.         {
  1499.             // No association found.
  1500.             string strError;
  1501.             strError = "There is currently no program associated with the '";
  1502.             strError += lvi->szExt;
  1503.             strError += "' file extension.  Use the 'File | Associate' menu option and try again.";
  1504.             MessageBox( strError.c_str(), "Unknown File Type", MB_ICONSTOP);
  1505.             return;
  1506.         }
  1507.  
  1508.         // Otherwise build a program + document command line.
  1509.         strcpy(szCmdLine, pThisFileAssoc->szEXEPathName);
  1510.  
  1511.         strcpy(szArgs, szCurrentListViewDir);
  1512.         strcat(szArgs, "\\");
  1513.         strcat(szArgs, lvi->szFileName);
  1514.  
  1515.         rc = RunProgramWithArgs(szCmdLine, szArgs);
  1516.         if(!rc)
  1517.             MessageBox("There was an error running this program.  Check that path is correct or close some programs to free up memory and try again.", "Can't Run", MB_ICONSTOP);
  1518.         return;
  1519.     }
  1520. }
  1521.  
  1522. void DFrame::SetupWindow()
  1523. {
  1524.     // Create listboxes
  1525.     FolderList = new CustomListBox(this, IDC_DIRLIST,
  1526.                             rFolderList.left,
  1527.                             rFolderList.top,
  1528.                             rFolderList.right - rFolderList.left,
  1529.                             rFolderList.bottom - rFolderList.top);
  1530.  
  1531.     FileList = new CustomListBox(this, IDC_FILELIST,
  1532.                                     rFileList.left,
  1533.                                     rFileList.top,
  1534.                                     rFileList.right - rFileList.left,
  1535.                                     rFileList.bottom - rFileList.top);
  1536.  
  1537.     FolderList->Attr.Style &= (LBS_SORT ^ 0xFFFFFFF); // Clear sort bit
  1538.     FolderList->Attr.Style |= LBS_OWNERDRAWFIXED;  // Make this 'ownerdraw'.
  1539.  
  1540.     FileList->Attr.Style &= (LBS_SORT ^ 0xFFFFFFF); // Clear sort bit
  1541.     FileList->Attr.Style |= LBS_MULTIPLESEL;
  1542.     FileList->Attr.Style |= LBS_OWNERDRAWFIXED;  // Make this 'ownerdraw'.
  1543.  
  1544.     TClientDC dcScreen(HWindow);
  1545.  
  1546.     dcMem = new TMemoryDC(dcScreen);
  1547.  
  1548.     // Positions to put info. in list box
  1549.     dcScreen.SelectObject(*pfontLB);
  1550.  
  1551.     TSize sizeText = dcScreen.GetTextExtent("XXXXX",5);
  1552.  
  1553.     cxName = sizeText.cx * 6;
  1554.     cxSize = sizeText.cx * 2;
  1555.     cxTimeStamp = sizeText.cx * 3 + sizeText.cx / 2;
  1556.     cxAttribute = sizeText.cx / 3;
  1557.  
  1558.     TWindow::SetupWindow();
  1559.  
  1560.     dcScreen.RestoreObjects();
  1561.  
  1562.     LoadInitDirs();
  1563.  
  1564.     pGlobalParent = this;
  1565.  
  1566.     nOldSortCheckedItem = CM_SORTNAME;
  1567. }
  1568.  
  1569. void DFrame::LoadInitDirs(void)
  1570. {
  1571.     char szTemp[8];
  1572.  
  1573.     TREEVIEW_ITEM tvi;
  1574.     tvi.nListBoxIndex = 0;  // Index # of this entry.
  1575.     tvi.nLevel = 1;         // In hierarchical list, this is the level of this entry
  1576.     tvi.nExpandCode = 1;    // 0 = Nothing to expand, 1 == Can Expand [+], 2 Already Expanded [-]
  1577.     tvi.bIsEndOfLevel = FALSE;
  1578.     tvi.Parent = NULL;
  1579.     tvi.lpszDirText = szTemp;
  1580.     tvi.nTextLen = 2;
  1581.  
  1582.     int nLastIndex = -1;
  1583.  
  1584.     // Go through possible letters for drives.
  1585.     int nTotalFound = 0;
  1586.     char szCurDir[257];
  1587.     char szTestFile[257];
  1588.  
  1589.     char szTestDir[10];
  1590.  
  1591.     int bUseCDImage = FALSE;
  1592.  
  1593.     int rc;
  1594.     char ch = 0;
  1595.  
  1596.     for(int i = 1; i < 26; i++)
  1597.     {
  1598.         // Turn off that ugly system message for not finding a disk (usually the A:/B: drives).
  1599.         DosError(FERR_DISABLEHARDERR);
  1600.         rc = getcurdir(i, szCurDir);
  1601.         if(rc == 0)
  1602.         {
  1603.             nTotalFound++;
  1604.             ch= 'A' + i - 1;
  1605.             tvi.nListBoxIndex = nTotalFound;  // Index # of this entry.
  1606.  
  1607.             if(ch == 'A' || ch == 'B')
  1608.             {
  1609.                 tvi.iImage = ID_FLOPPY;
  1610.                 tvi.iSelectedImage = ID_FLOPPY;
  1611.             }
  1612.             else
  1613.             {
  1614.                 // Check for CD-ROM drive.
  1615.                 char szDeviceName[8];
  1616.                 szDeviceName[0] = ch;
  1617.                 szDeviceName[1] = ':';
  1618.                 szDeviceName[2] = 0;
  1619.  
  1620.                 ULONG cbBuff;
  1621.  
  1622.                 BYTE FSInfo[sizeof(FSQBUFFER2) + 3 * 256];
  1623.                 PFSQBUFFER2  pfsqBuffer = (PFSQBUFFER2) FSInfo;
  1624.                 rc = DosQueryFSAttach(
  1625.                      szDeviceName,
  1626.                      0,
  1627.                      1,  // FSAIL_QUERYNAME
  1628.                      pfsqBuffer,
  1629.                      &cbBuff);
  1630.  
  1631.                 bUseCDImage = FALSE;
  1632.                 if(rc == 0)
  1633.                 {
  1634.                     // Offset is 11...
  1635.                     if(strcmpi(&FSInfo[11], "CDFS") == 0)
  1636.                         bUseCDImage = TRUE;
  1637.                 }
  1638.                 if(bUseCDImage)
  1639.                 {
  1640.                     tvi.iImage = ID_CDROM;
  1641.                     tvi.iSelectedImage = ID_CDROM;
  1642.                 }
  1643.                 else
  1644.                 {
  1645.                     tvi.iImage = ID_HDD;
  1646.                     tvi.iSelectedImage = ID_HDD;
  1647.                 }
  1648.             }
  1649.  
  1650.             szTemp[0] = ch;
  1651.             szTemp[1] = ':';
  1652.             szTemp[2] = 0;
  1653.  
  1654.             tvi.lpszDirText = new char[3];
  1655.             strcpy(tvi.lpszDirText, szTemp);
  1656.  
  1657.             tvi.nExpandCode = IsNextNodeExpandable(tvi.lpszDirText);
  1658.  
  1659.             nLastIndex = AddTreeViewItem(FolderList, tvi);
  1660.         }
  1661.     }
  1662.  
  1663.     // Mark last index as last item in root of hierarchy.
  1664.     if(nLastIndex > -1)
  1665.     {
  1666.         TREEVIEW_ITEM *pItem = (TREEVIEW_ITEM *)FolderList->GetItemData(nLastIndex);
  1667.         if(pItem)
  1668.             pItem->bIsEndOfLevel = TRUE;
  1669.     }
  1670.  
  1671.     // Re-paint our list.
  1672.     FolderList->Invalidate();
  1673. }
  1674.  
  1675. void DFrame::UpdateFileHdrText(LPSTR lpszNewText)
  1676. {
  1677.     if(lpszNewText)
  1678.         strFileHdr = lpszNewText;
  1679.  
  1680.     // Otherwise, just paint.
  1681.     TClientDC dc(HWindow);
  1682.  
  1683.     if(pfontWork)
  1684.         dc.SelectObject(*pfontWork);
  1685.  
  1686.     dc.ExtTextOut(rFileListHdr.left, rFileListHdr.top, ETO_CLIPPED | ETO_OPAQUE,
  1687.                       &rFileListHdr, strFileHdr.c_str(), strFileHdr.length(), NULL);
  1688. }
  1689.  
  1690. void DFrame::Paint(TDC& dc, BOOL erase, TRect& rect)
  1691. {
  1692.     TWindow::Paint(dc, erase, rect);
  1693.  
  1694.     if(pfontWork)
  1695.         dc.SelectObject(*pfontWork);
  1696.  
  1697.     // Paint Dir. Header
  1698.     dc.ExtTextOut(rFolderListHdr.left, rFolderListHdr.top, ETO_CLIPPED | ETO_OPAQUE,
  1699.                       &rFolderListHdr, strDirHdr.c_str(), strDirHdr.length(), NULL);
  1700.  
  1701.     // Paint Dir. Listbox
  1702.     FolderList->Invalidate(TRUE);
  1703.  
  1704.     // Paint Files Header
  1705.     dc.ExtTextOut(rFileListHdr.left, rFileListHdr.top, ETO_CLIPPED | ETO_OPAQUE,
  1706.                       &rFileListHdr, strFileHdr.c_str(), strFileHdr.length(), NULL);
  1707.  
  1708.     // Paint Files Listbox
  1709.     FileList->Invalidate(TRUE);
  1710.  
  1711.     // Update status bar.
  1712.     if(pStatusText)
  1713.         pStatusText->SetText(strStatus.c_str());
  1714.  
  1715.     dc.RestoreObjects();
  1716. }
  1717.  
  1718. void DFrame::DrawImage(TDC& dc, int nImage, int x, int y, UINT dwROP, BOOL bUseMask)
  1719. {
  1720.     // Renders image (a bitmap) to selected DC.
  1721.     if(nImage < 1 || nImage > MAXIMAGES - 1 || !dcMem)
  1722.     {
  1723. #ifdef __DEBUG
  1724.         MessageBox("Bad data in DrawImage()", "Error", MB_OK);
  1725. #endif
  1726.         return;
  1727.     }
  1728.  
  1729.     UINT dwUseROP = dwROP;
  1730.  
  1731.     TBitmap *pImage = ImageList[nImage];
  1732.  
  1733.     if(!pImage)
  1734.     {
  1735. #ifdef __DEBUG
  1736.         char szMsg[40];
  1737.         sprintf(szMsg, "Bad image index in DrawImage() = %d", nImage);
  1738.         MessageBox(szMsg, "Error", MB_OK);
  1739. #endif
  1740.         return;
  1741.     }
  1742.     dcMem->SelectObject(*ImageList[nImage]);
  1743.  
  1744.     if(bUseMask)
  1745.     {
  1746.         dc.SelectObject(*MaskBrush);
  1747.         dwUseROP = SRCCOPY;
  1748.     }
  1749.  
  1750.     dc.BitBlt(x, y, CXIMAGE, CYIMAGE, *dcMem, 0, 0, dwUseROP);
  1751. }
  1752.  
  1753. void DFrame::DrawSplitterWindowBar(TDC& dc, TRect& rect)
  1754. {
  1755.     dc.SelectStockObject(BLACK_PEN);
  1756.     dc.SelectStockObject(BLACK_BRUSH);
  1757.  
  1758.     dc.SetROP2(R2_NOT);
  1759.  
  1760.     dc.Rectangle(rect);
  1761.  
  1762.     dc.RestoreObjects();
  1763. }
  1764.  
  1765. void DFrame::EvLButtonDown(UINT keys, TPoint& point)
  1766. {
  1767.     TPoint ptMouse;
  1768.  
  1769.     if(rSplitter.Contains(point))
  1770.     {
  1771.         // Start splitter re-sizing operation.
  1772.         SetCapture();
  1773.         bResizingPanes = TRUE;
  1774.         bOverResizer = FALSE;
  1775.  
  1776.         TClientDC dc(HWindow);
  1777.  
  1778.         // Don't allow splitter to move all the way left or right.
  1779.         point.x = max(point.x, cyTitleBar);
  1780.         point.x = min(point.x, cxWin - 2 * cyTitleBar);
  1781.  
  1782.         rOldSplitter.Set(point.x - 3, rSplitter.top, point.x + 6 * cxBorder, rSplitter.bottom);
  1783.  
  1784.         DrawSplitterWindowBar(dc, rOldSplitter);
  1785.     }
  1786.     else
  1787.     {
  1788.         // Check if we're inside FileList folder rectangle for possible dragging.
  1789.         GetCursorPos(ptMouse);
  1790.         ScreenToClient(ptMouse);
  1791.  
  1792.         nFileListSelCount = FileList->GetSelCount();
  1793.  
  1794.         if(nFileListSelCount > 0 && rFileList.Contains(ptMouse))
  1795.         {
  1796.             if(nMouseBtnDownCode == NO_BTN)
  1797.             {
  1798.                 nMouseBtnDownCode = LEFT_BTN;
  1799.                 FileList->SetForwarding(TRUE);
  1800.                 FolderList->SetForwarding(TRUE);
  1801.             }
  1802.  
  1803.             if((bDragLeftBtn && nMouseBtnDownCode == RIGHT_BTN) ||
  1804.                 (!bDragLeftBtn && nMouseBtnDownCode == LEFT_BTN))
  1805.             {
  1806.                 // Then button prefs. don't match!
  1807.                 nMouseBtnDownCode = NO_BTN;
  1808.                 return;
  1809.             }
  1810.  
  1811.             bDragCopy = keys & CTRL_MOUSE_KEY ? TRUE : FALSE;
  1812.  
  1813.             SetCapture();
  1814.             bDraggingFiles = TRUE;
  1815.             bFirstDragMovement = TRUE;
  1816.  
  1817.             // Calculate possible targets--hit test triangles and their indexes in
  1818.             //    FolderList.
  1819.             int nTopIndex = FolderList->GetTopIndex();
  1820.  
  1821.             FolderDragTargets.Flush(TShouldDelete::Delete);
  1822.  
  1823.             TRect rItem;
  1824.             int rc;
  1825.  
  1826.             nTargetIndex = -1;
  1827.  
  1828.             TRect rActualFolder = FolderList->GetClientRect();
  1829.             int nCount = 0;
  1830.             // Collect hit test rectangles in targets
  1831.             int nItems = FolderList->GetCount();
  1832.             for(int i = nTopIndex; i < nItems; i++)
  1833.             {
  1834.                 rItem.Set(rActualFolder.left,
  1835.                              rActualFolder.top + nCount * CYLBHEIGHT,
  1836.                              rActualFolder.right,
  1837.                              rActualFolder.top + ((nCount + 1) * CYLBHEIGHT));
  1838.                 FolderDragTargets.Add(new LBHITTEST(i, rItem));
  1839.                 nCount++;
  1840.             }
  1841.             rOldRect.Set(-1,-1,-1,-1);
  1842.         }
  1843.         else if(rFolderList.Contains(ptMouse))
  1844.         {
  1845.             // Check for click over [+] or [-] rectangle.
  1846.             // This is an analogous operation to a double-click!!!
  1847.             int nTopIndex = FolderList->GetTopIndex();
  1848.  
  1849.             GetCursorPos(ptMouse);
  1850.             FolderList->ScreenToClient(ptMouse);
  1851.  
  1852.             TRect rExpandBox;
  1853.             TRect rActualFolder = FolderList->GetClientRect();
  1854.             // Collect hit test rectangles in targets
  1855.             int nItems = FolderList->GetCount();
  1856.             int nCount = 0;
  1857.             for(int i = nTopIndex; i < nItems; i++)
  1858.             {
  1859.                 // Check for all possible entries in this FolderList.
  1860.                 // First, check for [+] or [-]
  1861.                 TREEVIEW_ITEM *tvi = (TREEVIEW_ITEM *) FolderList->GetItemData(i);
  1862.                 if(!tvi || tvi->nExpandCode == 0)
  1863.                 {
  1864.                     nCount++;
  1865.                     continue;  // Go to next entry.
  1866.                 }
  1867.                 int cxStart = 0;
  1868.                 for(int ThisLevel = 0; ThisLevel < tvi->nLevel; ThisLevel++)
  1869.                 {
  1870.                     if(ThisLevel == 0)
  1871.                         cxStart = rActualFolder.left + 9;
  1872.                     else
  1873.                         cxStart += 20;
  1874.                 }
  1875.  
  1876.                 if(cxStart == 0)
  1877.                     cxStart = rActualFolder.left + 9;
  1878.  
  1879.                 // To here create our hit-test rectangle.
  1880.                 int cyMid = rActualFolder.top + nCount * CYLBHEIGHT + (CYLBHEIGHT / 2);
  1881.  
  1882.                 rExpandBox.Set(cxStart - 4,
  1883.                                     cyMid - 4,
  1884.                                     cxStart + 7,
  1885.                                     cyMid + 7);
  1886.  
  1887.                 if(rExpandBox.Contains(ptMouse))
  1888.                 {
  1889.                     // Simulate a double-click on this control.
  1890.                     FolderList->SetSelIndex(i);
  1891.                     OnFolderListDblClick();
  1892.                     return;
  1893.                 }
  1894.                 nCount++;
  1895.             }
  1896.         }
  1897.     }
  1898. }
  1899.  
  1900. void DFrame::EvMouseMove(UINT keys, TPoint& point)
  1901. {
  1902.     TPoint pt;
  1903.     GetCursorPos(pt);
  1904.     ScreenToClient(pt);
  1905.  
  1906.     TClientDC *pDC;
  1907.  
  1908.     if(bDraggingFiles)
  1909.     {
  1910.         TPoint ptMouse;
  1911.         GetCursorPos(ptMouse);
  1912.  
  1913.         bDragCopy = keys & CTRL_MOUSE_KEY ? TRUE : FALSE;
  1914.  
  1915.         // Check that we're inside DFrame
  1916.         TRect r;
  1917.         GetWindowRect(r);
  1918.  
  1919.         if(!r.Contains(ptMouse)) // If we're outside our frame initialize remote dragging.
  1920.         {
  1921.  
  1922.             if(rOldRect.left != -1)
  1923.             {
  1924.                 pDC = new TClientDC(FolderList->HWindow);
  1925.                 pDC->SetROP2(R2_NOT);
  1926.                 pDC->SelectStockObject(NULL_BRUSH);
  1927.                 pDC->SelectObject(*HighlightPen);
  1928.  
  1929.                 if(rOldRect.left != -1)
  1930.                     pDC->Rectangle(rOldRect);
  1931.  
  1932.                 pDC->RestoreObjects();
  1933.  
  1934.                 delete pDC;
  1935.  
  1936.                 rOldRect.Set(-1,-1,-1,-1);  // Nothing to erase next time.
  1937.             }
  1938.  
  1939.             nTargetIndex = -1;  // Not a local copy -- assume a remote copy to other OS/2 desktop objects.
  1940.  
  1941.             if(!bRemoteDraggingInit)
  1942.             {
  1943.                 // Start 'remote' dragging process--dragging to OS/2 desktop...
  1944.                 int nFiles = GetFileSelections();
  1945.                 if(!nFiles)
  1946.                     return;
  1947.  
  1948.                 pGlobalParent = this;
  1949.  
  1950.                 int nCount = CollectAllFilesInSelections(szCurrentListViewDir, szMask, ulShowAttrBits, szCurrentListViewDir);
  1951.                 if(nCount == 0)
  1952.                 {
  1953.                     MessageBox("Select some files first!", "No Files Selected", MB_ICONEXCLAMATION);
  1954.                     return;
  1955.                 }
  1956.  
  1957.                 ReleaseCapture();
  1958.                 int rc = InitDrag (WinQueryAnchorBlock(HWindow), HWindow, nCount, hptrFile,
  1959.                                 hptrFolder, hptrMulti, szCurrentListViewDir);
  1960.                 if(rc)
  1961.                 {
  1962.                     bDraggingFiles = FALSE;
  1963.                     OnFolderListClick();
  1964.                     ShowArrowCursor();
  1965.                 }
  1966.                 else
  1967.                     SetCapture();
  1968.             }
  1969.         }
  1970.         else
  1971.         {
  1972.             FolderList->ScreenToClient(ptMouse);
  1973.  
  1974.             // Drag files support.
  1975.  
  1976.             // Change cursor to appropriate pointer/cursor
  1977.             SetCursor(GetModule(), bDragCopy ? ID_COPY_DOCS : ID_MOVE_DOCS);
  1978.  
  1979.             bFirstDragMovement = FALSE;
  1980.  
  1981.             TPoint ptMouse;
  1982.             GetCursorPos(ptMouse);
  1983.             FolderList->ScreenToClient(ptMouse);
  1984.  
  1985.             LBHITTEST *pTestIt;
  1986.  
  1987.             pDC = new TClientDC(FolderList->HWindow);
  1988.             pDC->SetROP2(R2_NOT);
  1989.             pDC->SelectStockObject(NULL_BRUSH);
  1990.             pDC->SelectObject(*HighlightPen);
  1991.  
  1992.             nTargetIndex = -1;  // Cancel out old target index.
  1993.  
  1994.             if(rOldRect.left != -1)
  1995.                 pDC->Rectangle(rOldRect);
  1996.  
  1997.             for(int i = 0; i < FolderDragTargets.GetItemsInContainer(); i++)
  1998.             {
  1999.                 pTestIt = FolderDragTargets[i];
  2000.                 if(!pTestIt)
  2001.                     continue;
  2002.  
  2003.                 if(pTestIt->rect.Contains(ptMouse))
  2004.                 {
  2005.                     // A match! -- highlight this rectangle.
  2006.                     // Unselect old rectangle first!
  2007.                     pDC->Rectangle(pTestIt->rect);
  2008.                     rOldRect = pTestIt->rect;
  2009.                     nTargetIndex = pTestIt->nIndex;
  2010.                     break;
  2011.                 }
  2012.             }
  2013.             if(nTargetIndex == -1)
  2014.                 rOldRect.Set(-1,-1,-1,-1);  // Nothing to erase next time.
  2015.  
  2016.             pDC->RestoreObjects();
  2017.  
  2018.             delete pDC;
  2019.         }
  2020.     }
  2021.     else if(!bOverResizer)
  2022.     {
  2023.         // Check for hit-test over 'splitter' area.
  2024.         if(rSplitter.Contains(point))
  2025.         {
  2026.             SetCursor(0, IDC_SIZEWE);
  2027.             bOverResizer = TRUE;
  2028.         }
  2029.     }
  2030.     else if(bOverResizer)
  2031.     {
  2032.         if(bResizingPanes)  // Then set cursor to re-size in all cases.
  2033.                                   // Update splitter bar.
  2034.         {
  2035.             SetCursor(0, IDC_SIZEWE);
  2036.  
  2037.             TClientDC dc(HWindow);
  2038.  
  2039.             // Erase bar at previous position
  2040.             DrawSplitterWindowBar(dc, rOldSplitter);
  2041.  
  2042.             // In all cases, update splitter window and save old position
  2043.  
  2044.             // Don't allow splitter to move all the way left or right.
  2045.             if(pt.x < 0) // Special case, mouse left of window.
  2046.                 point.x = cyTitleBar;
  2047.             else
  2048.             {
  2049.                 point.x = max(point.x, cyTitleBar);
  2050.                 point.x = min(point.x, cxWin - 2 * cyTitleBar);
  2051.             }
  2052.  
  2053.             rOldSplitter.Set(point.x - 3, rSplitter.top, point.x + 6 * cxBorder, rSplitter.bottom);
  2054.  
  2055.             DrawSplitterWindowBar(dc, rOldSplitter);
  2056.         }
  2057.         else
  2058.         {
  2059.             // Check for hit-test over 'splitter' area.
  2060.             if(rSplitter.Contains(point))
  2061.             {
  2062.                 SetCursor(0, IDC_SIZEWE);
  2063.                 bOverResizer = TRUE;
  2064.             }
  2065.             else
  2066.             {
  2067.                 // Then we're no longer over splitter area.
  2068.                 ShowArrowCursor();
  2069.                 bOverResizer = FALSE;
  2070.             }
  2071.         }
  2072.     }
  2073.     else
  2074.     {
  2075.         SetCursor(0, IDC_ARROW);
  2076.         bOverResizer = FALSE;
  2077.     }
  2078. }
  2079.  
  2080. void DFrame::EvRButtonUp(UINT keys, TPoint& point)
  2081. {
  2082.     nMouseBtnDownCode = NO_BTN;
  2083.     bCouldDrag = FALSE;
  2084.  
  2085.     EvLButtonUp(keys, point);
  2086.  
  2087.     FileList->SetForwarding(FALSE);
  2088.     FolderList->SetForwarding(FALSE);
  2089.  
  2090.     bLocalDragging = FALSE;
  2091.     bRemoteDragging = FALSE;
  2092.     bRemoteDraggingInit = FALSE;
  2093.  
  2094.     keys; point; // Kill warnings.
  2095. }
  2096.  
  2097. void DFrame::EvLButtonUp(UINT keys, TPoint& point)
  2098. {
  2099.     TClientDC *dcFolder = NULL;
  2100.  
  2101.     if(bResizingPanes)
  2102.     {
  2103.         // End splitter re-sizing operation.
  2104.         ReleaseCapture();
  2105.         bResizingPanes = FALSE;
  2106.         bOverResizer = FALSE;
  2107.  
  2108.         // Re-draw both headers and list boxes with new size, if we've moved.
  2109.         TClientDC dc(HWindow);
  2110.  
  2111.         // Erase bar at previous position
  2112.         DrawSplitterWindowBar(dc, rOldSplitter);
  2113.  
  2114.         cxCurrentDir = rOldSplitter.left + 5;
  2115.  
  2116.         // Simulate a re-size operation.  This re-paints us with new dimensions.
  2117.         TSize size(cxWin, cyWin);
  2118.         EvSize(0, size);
  2119.     }
  2120.     else if(bDraggingFiles)
  2121.     {
  2122.         // Process drag over to folder, if one is selected.
  2123.         // Assumes bDragCopy is previously set (it should be).
  2124.  
  2125.         // Clean-up for next time.
  2126.         ReleaseCapture();
  2127.         ShowArrowCursor();
  2128.         bDraggingFiles = FALSE;
  2129.  
  2130.         int bFilesCouldHaveChanged = FALSE;
  2131.  
  2132.         FolderDragTargets.Flush(TShouldDelete::Delete);
  2133.  
  2134.         if(nTargetIndex != -1)
  2135.         {
  2136.             int rc;
  2137.             while(1)  // For flow control
  2138.             {
  2139.                 string strTargetDir;
  2140.  
  2141.                 rc = GetSelectedDir(strTargetDir, nTargetIndex);
  2142.                 if(!rc)
  2143.                     break;
  2144.  
  2145.                 // Now get selected files.
  2146.                 int n = GetFileSelections();
  2147.                 if(n == 0)
  2148.                     break;
  2149.  
  2150.                 if(strTargetDir == szCurrentListViewDir)
  2151.                 {
  2152.                     MessageBox("Source and target directories are the same.",
  2153.                                     bDragCopy ? "Can't Copy Files" : "Can't Move Files",
  2154.                                     MB_ICONEXCLAMATION);
  2155.                     break;
  2156.                 }
  2157.  
  2158.                 char szFullTarget[256];
  2159.                 char szTargetDir[256];
  2160.  
  2161.                 string strTestDir;
  2162.  
  2163.                 string strAll("*.*");
  2164.                 size_t pos = strTargetDir.find_first_of(strAll);
  2165.  
  2166.                 if(pos != NPOS)
  2167.                     strTargetDir = strTargetDir.substr(0, pos - 1);
  2168.  
  2169.                 ShowWaitCursor();
  2170.  
  2171.                 pStatusText->SetText("Computing total size...");
  2172.  
  2173.                 int nCount = CollectAllFilesInSelections((LPSTR)strTargetDir.c_str(), szMask, ulShowAttrBits, szCurrentListViewDir);
  2174.                 if(nCount == 0)
  2175.                 {
  2176.                     MessageBox("Select some files first!", "No Files Selected", MB_ICONEXCLAMATION);
  2177.                     break;
  2178.                 }
  2179.  
  2180.                 ShowArrowCursor();
  2181.                 pStatusText->SetText("");
  2182.  
  2183.                 static FILEOPPARAM FileOpParam;
  2184.                 FileOpParam.pStatus = pGlobalStatusBar;
  2185.                 FileOpParam.pParent = pGlobalParent;
  2186.                 FileOpParam.lpszSourceDir = szCurrentListViewDir;
  2187.                 FileOpParam.lpszTargetDir = (LPSTR)strTargetDir.c_str();
  2188.                 static char szNoFile[] = "";
  2189.                 FileOpParam.lpszTargetFile = szNoFile; // Not used here.
  2190.  
  2191.                 string strConfirm("Are you sure you want to ");
  2192.  
  2193.                 string strPlural("");
  2194.  
  2195.                 char szTotal[20];
  2196.  
  2197.                 if((bDragCopy && bConfirmCopy) || (!bDragCopy && bConfirmDelete) || bConfirmAll)
  2198.                 {
  2199.                     itoa(nCount, szTotal, 10);
  2200.  
  2201.                     if(nCount == 1)
  2202.                         strPlural = "";
  2203.                     else
  2204.                         strPlural = "s";
  2205.  
  2206.                     // Load up our text.
  2207.                     if(bDragCopy)
  2208.                         strConfirm += "copy ";
  2209.                     else
  2210.                         strConfirm += "move ";
  2211.  
  2212.                     strConfirm += szTotal;
  2213.                     strConfirm += " object";
  2214.                     strConfirm += strPlural;
  2215.                     strConfirm += " (";
  2216.                     strConfirm += GetFileSizeAsStr(ulTotalFilesBytes);
  2217.                     strConfirm += ") to ";
  2218.                     strConfirm += strTargetDir;
  2219.                     strConfirm += "?";
  2220.                     rc = MessageBox(strConfirm.c_str(),
  2221.                                          bDragCopy ? "Confirm Copy" : "Confirm Move",
  2222.                                          MB_YESNOCANCEL);
  2223.                     if(rc != IDYES)
  2224.                     {
  2225.                         CleanupArrays();
  2226.                         break;
  2227.                     }
  2228.                 }
  2229.  
  2230.                 bFilesCouldHaveChanged = TRUE;
  2231.  
  2232.                 FileOpParam.lpszTargetDir = (LPSTR)strTargetDir.c_str();
  2233.                 FileOpParam.nFileOp = bDragCopy ? CM_COPY : CM_MOVE;
  2234.  
  2235.                 rc = CopyOrMoveFiles(&FileOpParam);
  2236.                 if(!rc)
  2237.                     MessageBox(bDragCopy ? "Can't copy files!" : "Can't move files!",
  2238.                                   "File Operation Failed", MB_ICONSTOP);
  2239.                 CleanupArrays();
  2240.  
  2241.                 if(pStatusText)
  2242.                     pStatusText->SetText("");
  2243.  
  2244.                 break;  // In all cases exit our 'dummy' while loop.
  2245.             }
  2246.         }
  2247.         if(rOldRect.left != -1)
  2248.         {
  2249.             // Erase last highlighted rectangle.
  2250.             dcFolder = new TClientDC(FolderList->HWindow);
  2251.             dcFolder->SetROP2(R2_NOT);
  2252.             dcFolder->SelectStockObject(NULL_BRUSH);
  2253.             dcFolder->SelectObject(*HighlightPen);
  2254.             dcFolder->Rectangle(rOldRect);
  2255.             dcFolder->RestoreObjects();
  2256.             delete dcFolder;
  2257.         }
  2258.         if(bFilesCouldHaveChanged)
  2259.             // Refresh files list as necessary.
  2260.             OnFolderListClick();
  2261.     }
  2262.     else
  2263.     {
  2264.         bResizingPanes = FALSE;
  2265.         bOverResizer = FALSE;
  2266.     }
  2267.  
  2268.     nMouseBtnDownCode = NO_BTN;
  2269.     bCouldDrag = FALSE;
  2270.  
  2271.     bLocalDragging = FALSE;
  2272.     bRemoteDragging = FALSE;
  2273.     bRemoteDraggingInit = FALSE;
  2274.  
  2275.     keys; point; //  Kill warnings;
  2276. }
  2277.  
  2278. void DFrame::CmEnableOpen(TCommandEnabler& ce)
  2279. {
  2280.     // Enable/disable Open option.
  2281.     // Open option requires that only one file be selected.
  2282.     if(nFileListSelCount == 1)
  2283.         ce.Enable(TRUE);
  2284.     else
  2285.         ce.Enable(FALSE);
  2286. }
  2287.  
  2288. void DFrame::CmEnableMove(TCommandEnabler& ce)
  2289. {
  2290.     if(nFileListSelCount > 0)
  2291.         ce.Enable(TRUE);
  2292.     else
  2293.         ce.Enable(FALSE);
  2294. }
  2295.  
  2296. void DFrame::CmEnableCopy(TCommandEnabler& ce)
  2297. {
  2298.     if(nFileListSelCount > 0)
  2299.         ce.Enable(TRUE);
  2300.     else
  2301.         ce.Enable(FALSE);
  2302. }
  2303.  
  2304. void DFrame::CmEnableDelete(TCommandEnabler& ce)
  2305. {
  2306.     int nIndex = FolderList->GetSelIndex();
  2307.     if(nIndex > -1)
  2308.         ce.Enable(TRUE);
  2309.     else
  2310.         ce.Enable(FALSE);
  2311. }
  2312.  
  2313. void DFrame::CmEnableProperties(TCommandEnabler& ce)
  2314. {
  2315.     if(nFileListSelCount > 0)
  2316.         ce.Enable(TRUE);
  2317.     else
  2318.         ce.Enable(FALSE);
  2319. }
  2320.  
  2321. void DFrame::CmOpen()
  2322. {
  2323.     // Run currently selected (only one) file.
  2324.     int anSelIndexes[MAXENTRIES];
  2325.     int nCount = FileList->GetSelIndexes(anSelIndexes, MAXENTRIES);
  2326.     if(nCount > 0)
  2327.     {
  2328.         nOpenFileIndex = anSelIndexes[0];
  2329.         OnFileListDblClick();
  2330.         nOpenFileIndex = -1;
  2331.     }
  2332. }
  2333.  
  2334. void DFrame::CmMove()
  2335. {
  2336.     int n = GetFileSelections();
  2337.  
  2338.     if(n == 0)
  2339.         return;
  2340.  
  2341.     DFileChangeDlg MoveDlg(this, szCurrentListViewDir, CM_MOVE);
  2342.     MoveDlg.Execute();
  2343.     CmRefreshOneFolder();
  2344. }
  2345.  
  2346. void DFrame::CmCopy()
  2347. {
  2348.     int n = GetFileSelections();
  2349.  
  2350.     if(n == 0)
  2351.         return;
  2352.  
  2353.     DFileChangeDlg CopyDlg(this, szCurrentListViewDir, CM_COPY);
  2354.     CopyDlg.Execute();
  2355.     CmRefreshOneFolder();
  2356. }
  2357.  
  2358. void DFrame::CmDelete()
  2359. {
  2360.     int rc;
  2361.     TREEVIEW_ITEM *tvi;
  2362.  
  2363.     if(bFolderOnlyNoSelections && strlen(szCurrentListViewDir) > 2)   // Not root.
  2364.     {
  2365.         int nIndex = FolderList->GetSelIndex();
  2366.         if(nIndex < 0)
  2367.             return;
  2368.         string strMsg = "Remove empty directory ";
  2369.         strMsg += szCurrentListViewDir;
  2370.         rc = MessageBox((LPSTR)strMsg.c_str(), "Confirm Delete", MB_YESNOCANCEL);
  2371.         if(rc != IDYES)
  2372.             return;
  2373.         char szRootDir[8];
  2374.         szRootDir[0] = szCurrentListViewDir[0];
  2375.         szRootDir[1] = '\\';
  2376.         szRootDir[2] = ';';
  2377.         szRootDir[3] = 0;
  2378.         chdir(szRootDir);
  2379.         rc = DosDeleteDir(szCurrentListViewDir);
  2380.         if(rc)
  2381.             MessageBox("Unable to remove this directory.", "Can't Remove Directory", MB_ICONEXCLAMATION);
  2382.         else
  2383.         {
  2384.             if(nIndex > 0)
  2385.             {
  2386.                 string strNewDir;
  2387.                 int nNewIndex = nIndex - 1;
  2388.                 tvi = (TREEVIEW_ITEM *)FolderList->GetItemData(nIndex);
  2389.                 if(!tvi)
  2390.                 {
  2391.                     CmRefreshAllFolders();
  2392.                     return;
  2393.                 }
  2394.                 int nOldLevel = tvi->nLevel;
  2395.  
  2396.                 FolderList->SetSelIndex(nNewIndex);
  2397.                 tvi = (TREEVIEW_ITEM *)FolderList->GetItemData(nNewIndex);
  2398.                 if(!tvi)
  2399.                 {
  2400.                     CmRefreshAllFolders();
  2401.                     return;
  2402.                 }
  2403.  
  2404.                 FolderList->DeleteString(nIndex);
  2405.  
  2406.                 if(tvi->nLevel < nOldLevel)
  2407.                 {
  2408.                     rc = GetSelectedDir(strNewDir, nNewIndex);
  2409.                     if(rc)
  2410.                     {
  2411.                         rc = IsNextNodeExpandable((LPSTR)strNewDir.c_str());
  2412.                         if(!rc)
  2413.                         {
  2414.                             // This was the last entry in an expandable branch.
  2415.                             // Mark it as no longer expandable and reload this instance.
  2416.                             if(tvi->nExpandCode == 1 || tvi->nExpandCode == 2)
  2417.                             {
  2418.                                 tvi->nExpandCode = 0;
  2419.                                 FolderList->DeleteString(nNewIndex);
  2420.                                 AddTreeViewItem(FolderList, *tvi, nNewIndex);
  2421.                             }
  2422.                         }
  2423.                         FolderList->SetSelIndex(nNewIndex);
  2424.                     }
  2425.                     else
  2426.                     {
  2427.                         CmRefreshAllFolders();
  2428.                         return;
  2429.                     }
  2430.                 }
  2431.                 else
  2432.                     CmRefreshAllFolders();
  2433.             }
  2434.             else
  2435.                 CmRefreshAllFolders();
  2436.         }
  2437.     }
  2438.     int n = GetFileSelections();
  2439.  
  2440.     if(n == 0)
  2441.         return;
  2442.  
  2443.     DFileChangeDlg DeleteDlg(this,  szCurrentListViewDir, CM_DELETE);
  2444.     rc = DeleteDlg.Execute();
  2445.     CmRefreshOneFolder();
  2446. }
  2447.  
  2448. void DFrame::CmRun()
  2449. {
  2450.     int nSelCount = GetFileSelections();
  2451.  
  2452.     FILEENTRY *pFileEntry = NULL;
  2453.  
  2454.     static char szNothing[2] = "";
  2455.  
  2456.     LPSTR lpszMyInitCmd = szNothing;
  2457.  
  2458.     if(nSelCount > 0)
  2459.     {
  2460.         pFileEntry = (FILEENTRY *)SelectedFileList[0];
  2461.         if(pFileEntry)
  2462.             lpszMyInitCmd = pFileEntry->szFileName;
  2463.     }
  2464.  
  2465.     DRunCmdDlg RunCommandDlg(this, szCurrentListViewDir, lpszMyInitCmd);
  2466.  
  2467.     RunCommandDlg.Execute();
  2468. }
  2469.  
  2470. void DFrame::CmProperties()
  2471. {
  2472.     int n = GetFileSelections();
  2473.     if(n == 0)
  2474.         return;
  2475.  
  2476.     DFilePropertiesDlg SetFilePropertiesDlg(this, szCurrentListViewDir);
  2477.     SetFilePropertiesDlg.Execute();
  2478.     OnFolderListClick();
  2479. }
  2480.  
  2481. void DFrame::CmCreateDir()
  2482. {
  2483.     DCreateDirDlg CreateNewDirDlg(this, szCurrentListViewDir);
  2484.  
  2485.     CreateNewDirDlg.Execute();
  2486.     CmRefreshOneFolder();
  2487. }
  2488.  
  2489. void DFrame::CmAssociate()
  2490. {
  2491.     char szNewExt[4];
  2492.  
  2493.     szNewExt[0] = 0;
  2494.  
  2495.     // Show 'File Associations' dialog box.
  2496.     DAssociationsDlg FileAssocDlg(this, &FileAssociations, szNewExt);
  2497.     FileAssocDlg.Execute();
  2498. }
  2499.  
  2500. void DFrame::CmExit()
  2501. {
  2502.     if(pFrame)
  2503.         pFrame->CloseWindow();   // Close our application.
  2504. }
  2505.  
  2506. void DFrame::CmSelectFiles()
  2507. {
  2508.     // Allow user to specify a wildcard and choose files in current directory.
  2509.     if(strlen(szCurrentListViewDir) == 0)
  2510.         return;  // Must have some files.
  2511.  
  2512.     DSelFilesDlg SelectFilesDlg(this, szSelByMask);
  2513.     int rc = SelectFilesDlg.Execute();
  2514.     if(rc)
  2515.     {
  2516.         int bDeselecting = rc == -5 ? TRUE : FALSE;
  2517.  
  2518.         FILEENTRY *pFileEntry = NULL;
  2519.  
  2520.         string strTestIt;
  2521.         string strNew;
  2522.  
  2523.         strTestIt.set_case_sensitive(0);
  2524.         strNew.set_case_sensitive(0);
  2525.  
  2526.         string strSelByMask(szSelByMask);
  2527.         string strErr;
  2528.  
  2529.         int bIsSelected;
  2530.  
  2531.         ShowWaitCursor();
  2532.  
  2533.         // Then walk through current file list and select all files
  2534.         // that match this pattern.
  2535.         for(int i = 0; i < FileList->GetCount(); i++)
  2536.         {
  2537.             pFileEntry = (FILEENTRY *)FileList->GetItemData(i);
  2538.             if(!pFileEntry || pFileEntry->nType == 1)  // Skip bad entries and directories.
  2539.                 continue;
  2540.  
  2541.             strTestIt = "X:\\";   // Dummy fully qualified path--this is needed for the upcoming call.
  2542.             strTestIt += pFileEntry->szFileName;
  2543.  
  2544.             rc = MakeNewSourcePathWithWildcardMask(strNew, strTestIt, strSelByMask, strErr);
  2545.             if(rc && (strNew == strTestIt))
  2546.                 FileList->SetSel(i, !bDeselecting);  // Then select or de-select this file.
  2547.         }
  2548.         ShowArrowCursor();
  2549.     }
  2550. }
  2551.  
  2552. void DFrame::CmSelectAll()
  2553. {
  2554.     int nCount = FileList->GetCount();
  2555.  
  2556.     FileList->SetSelItemRange(TRUE, 0, nCount - 1);
  2557. }
  2558.  
  2559. void DFrame::CmSelectNone()
  2560. {
  2561.     int nCount = FileList->GetCount();
  2562.  
  2563.     FileList->SetSelItemRange(FALSE, 0, nCount - 1);
  2564. }
  2565.  
  2566. void DFrame::CmShowName()
  2567. {
  2568.     if(pFrame)
  2569.     {
  2570.         hwndMenu = WinWindowFromID(pFrame->HWindow, FID_MENU);
  2571.         WinCheckMenuItem(hwndMenu, CM_FILE_NAME, TRUE);
  2572.         WinCheckMenuItem(hwndMenu, CM_ALL_DETAILS, FALSE);
  2573.         WinCheckMenuItem(hwndMenu, CM_PARTIAL_DETAILS, FALSE);
  2574.     }
  2575.     // Then show file details.
  2576.     bShowAllFileDetails = FALSE;
  2577.  
  2578.     bShowSize = FALSE;
  2579.     bShowTimeStamp = FALSE;
  2580.     bShowAttr = FALSE;
  2581.  
  2582.     OnFolderListClick();
  2583. }
  2584.  
  2585. void DFrame::CmAllFileDetails()
  2586. {
  2587.     if(pFrame)
  2588.     {
  2589.         hwndMenu = WinWindowFromID(pFrame->HWindow, FID_MENU);
  2590.         WinCheckMenuItem(hwndMenu, CM_FILE_NAME, FALSE);
  2591.         WinCheckMenuItem(hwndMenu, CM_ALL_DETAILS, TRUE);
  2592.         WinCheckMenuItem(hwndMenu, CM_PARTIAL_DETAILS, FALSE);
  2593.     }
  2594.  
  2595.     bShowSize = TRUE;
  2596.     bShowTimeStamp = TRUE;
  2597.     bShowAttr = TRUE;
  2598.  
  2599.     OnFolderListClick();
  2600. }
  2601.  
  2602. void DFrame::CmPartialFileDetails()
  2603. {
  2604.     // Show partial file options dialog box.
  2605.     DFileDetailsDlg FileDetailsDlg(this, &bShowTimeStamp,
  2606.                     &bShowAttr, &bShowSize);
  2607.     int rc = FileDetailsDlg.Execute();
  2608.  
  2609.     if(rc)
  2610.     {
  2611.         if(pFrame)
  2612.         {
  2613.             hwndMenu = WinWindowFromID(pFrame->HWindow, FID_MENU);
  2614.             WinCheckMenuItem(hwndMenu, CM_FILE_NAME, FALSE);
  2615.             WinCheckMenuItem(hwndMenu, CM_ALL_DETAILS, FALSE);
  2616.             WinCheckMenuItem(hwndMenu, CM_PARTIAL_DETAILS, TRUE);
  2617.         }
  2618.         // Then repaint our dialog with new info.
  2619.         FileList->Invalidate();
  2620.     }
  2621. }
  2622.  
  2623. void DFrame::CmRefreshOneFolder()
  2624. {
  2625.     OnFolderListClick();
  2626. }
  2627.  
  2628. void DFrame::CmRefreshAllFolders()
  2629. {
  2630.     // Clear and re-load.
  2631.     ClearFolderList();
  2632.     ClearFileList();
  2633.  
  2634.     // Clear and re-load.
  2635.     LoadInitDirs();
  2636. }
  2637.  
  2638. void DFrame::CmDragWithLeftBtn()
  2639. {
  2640.     if(pFrame)
  2641.     {
  2642.         hwndMenu = WinWindowFromID(pFrame->HWindow, FID_MENU);
  2643.         bDragLeftBtn = !bDragLeftBtn;
  2644.         // If we're dragging with copy, the move option is NOT checked.
  2645.         WinCheckMenuItem(hwndMenu, CM_DRAG_LEFT_BTN, bDragLeftBtn);
  2646.     }
  2647. }
  2648.  
  2649. void DFrame::CmShowFileTypes()
  2650. {
  2651.     DFileMaskDlg SetFileMaskDlg(this, szMask, &bShowHiddenOrSysObjs);
  2652.  
  2653.     int rc = SetFileMaskDlg.Execute();
  2654.     if(rc)
  2655.         // If we've set new view options, re-load files.
  2656.         OnFolderListClick();
  2657. }
  2658.  
  2659. void DFrame::CmSortByName()
  2660. {
  2661.     if(nSortCode != SORT_BY_NAME)
  2662.     {
  2663.         ResortFileEntries(SORT_BY_NAME);
  2664.  
  2665.         nSortCode = SORT_BY_NAME;
  2666.  
  2667.         if(pFrame)
  2668.         {
  2669.             hwndMenu = WinWindowFromID(pFrame->HWindow, FID_MENU);
  2670.  
  2671.             WinCheckMenuItem(hwndMenu, nOldSortCheckedItem, 0);
  2672.             nOldSortCheckedItem = CM_SORTNAME;
  2673.             WinCheckMenuItem(hwndMenu, nOldSortCheckedItem, 1);
  2674.         }
  2675.         FileList->Invalidate();
  2676.     }
  2677. }
  2678.  
  2679. void DFrame::CmSortByType()
  2680. {
  2681.     if(nSortCode != SORT_BY_EXT)
  2682.     {
  2683.         ResortFileEntries(SORT_BY_EXT);
  2684.  
  2685.         nSortCode = SORT_BY_EXT;
  2686.  
  2687.         if(pFrame)
  2688.         {
  2689.             hwndMenu = WinWindowFromID(pFrame->HWindow, FID_MENU);
  2690.             WinCheckMenuItem(hwndMenu, nOldSortCheckedItem, 0);
  2691.             nOldSortCheckedItem = CM_SORTTYPE;
  2692.             WinCheckMenuItem(hwndMenu, nOldSortCheckedItem, 1);
  2693.         }
  2694.         FileList->Invalidate();
  2695.     }
  2696. }
  2697.  
  2698. void DFrame::CmSortBySize()
  2699. {
  2700.     if(nSortCode != SORT_BY_SIZE)
  2701.     {
  2702.         ResortFileEntries(SORT_BY_SIZE);
  2703.  
  2704.         nSortCode = SORT_BY_SIZE;
  2705.  
  2706.         if(pFrame)
  2707.         {
  2708.             hwndMenu = WinWindowFromID(pFrame->HWindow, FID_MENU);
  2709.             WinCheckMenuItem(hwndMenu, nOldSortCheckedItem, 0);
  2710.             nOldSortCheckedItem = CM_SORTSIZE;
  2711.             WinCheckMenuItem(hwndMenu, nOldSortCheckedItem, 1);
  2712.         }
  2713.         FileList->Invalidate();
  2714.     }
  2715. }
  2716.  
  2717. void DFrame::CmSortByDate()
  2718. {
  2719.     if(nSortCode != SORT_BY_DATE)
  2720.     {
  2721.         ResortFileEntries(SORT_BY_DATE);
  2722.  
  2723.         nSortCode = SORT_BY_DATE;
  2724.  
  2725.         if(pFrame)
  2726.         {
  2727.             hwndMenu = WinWindowFromID(pFrame->HWindow, FID_MENU);
  2728.             WinCheckMenuItem(hwndMenu, nOldSortCheckedItem, 0);
  2729.             nOldSortCheckedItem = CM_SORTDATE;
  2730.             WinCheckMenuItem(hwndMenu, nOldSortCheckedItem, 1);
  2731.         }
  2732.         FileList->Invalidate();
  2733.     }
  2734. }
  2735.  
  2736. void DFrame::CmConfirmOptions()
  2737. {
  2738.     // Show confirmation options dialog box.
  2739.     DConfirmDlg ConfirmOpts(this, &bConfirmDelete, &bConfirmReplace, &bConfirmCopy, &bConfirmAll);
  2740.     ConfirmOpts.Execute();
  2741. }
  2742.  
  2743. void DFrame::CmAbout()
  2744. {
  2745.     TDialog AboutDlg(this, IDD_ABOUT);
  2746.     AboutDlg.Execute();
  2747. }
  2748.  
  2749. int DFrame::GetFileSelections()
  2750. {
  2751.     int anSelIndexes[MAXENTRIES];
  2752.  
  2753.     SelectedFileList.Flush(TShouldDelete::NoDelete);
  2754.  
  2755.     int nCount = FileList->GetSelIndexes(anSelIndexes, MAXENTRIES);
  2756.  
  2757.     FILEENTRY *lvi;
  2758.  
  2759.     pGlobalParent = this;
  2760.  
  2761.     for(int i = 0; i < nCount; i++)
  2762.     {
  2763.         lvi = (FILEENTRY *)FileList->GetItemData(anSelIndexes[i]);
  2764.         if(lvi)
  2765.             SelectedFileList.Add(lvi);
  2766.     }
  2767.  
  2768.     nFileListSelCount = SelectedFileList.GetItemsInContainer();
  2769.  
  2770.     return nFileListSelCount;
  2771. }
  2772.  
  2773. int DFrame::GetFileListDblClickIndex()
  2774. {
  2775.     // Retrieves index of double-clicked item, at
  2776.     int nTopIndex = FileList->GetTopIndex();
  2777.  
  2778.     TRect rItem;
  2779.     int rc;
  2780.  
  2781.     nTargetIndex = -1;
  2782.  
  2783.     TRect rActualFiles = FileList->GetClientRect();
  2784.     int nCount = 0;
  2785.  
  2786.     TPoint pt;
  2787.     GetCursorPos(pt);
  2788.     FileList->ScreenToClient(pt);
  2789.  
  2790.     // Test for hit-test in our list box.
  2791.     int nItems = FileList->GetCount();
  2792.  
  2793.     int nFoundIndex = -1;
  2794.     for(int i = nTopIndex; i < nItems; i++)
  2795.     {
  2796.         rItem.Set(rActualFiles.left,
  2797.                     rActualFiles.top + nCount * CYLBHEIGHT,
  2798.                     rActualFiles.right,
  2799.                     rActualFiles.top + ((nCount + 1) * CYLBHEIGHT));
  2800.  
  2801.         if(rItem.Contains(pt))
  2802.         {
  2803.             nFoundIndex = i;
  2804.             break;
  2805.         }
  2806.         nCount++;
  2807.     }
  2808.     if(nFoundIndex > -1)
  2809.         return nFoundIndex;
  2810.     else
  2811.         return -1;
  2812. }
  2813.  
  2814. void DFrame::EvSize(uint sizeType, TSize& size)
  2815. {
  2816.     // Resize our on-screen objects.
  2817.  
  2818.     // Call parent's method first.--This re-sizes status bar at bottom of screen.
  2819.     TWindow::EvSize(sizeType, size);
  2820.  
  2821.     cxWin = size.cx;
  2822.     cyWin = size.cy;
  2823.  
  2824.     // If first time with sizing, use mid-point of window for directory listbox.
  2825.     if(cxCurrentDir == 0)
  2826.         cxCurrentDir = cxWin / 3 - 4 * cxBorder;
  2827.  
  2828.     // Re-size our rectangles.
  2829.  
  2830.     // Column Header (Left)
  2831.     rFolderListHdr.left = 2 * cxBorder;
  2832.     rFolderListHdr.top = 2 * cxBorder;
  2833.     rFolderListHdr.right = rFolderListHdr.left + cxCurrentDir;
  2834.     rFolderListHdr.bottom = rFolderListHdr.top + cyTitleBar + 2 * cxBorder;
  2835.  
  2836.     // Left Listbox (Folders/Dir.'s)
  2837.     rFolderList.left = rFolderListHdr.left;
  2838.     rFolderList.top = rFolderListHdr.bottom + 2 * cxBorder;
  2839.     rFolderList.right = rFolderListHdr.right;
  2840.     rFolderList.bottom = cyWin - 2 * cxBorder;
  2841.  
  2842.     FolderList->MoveWindow(rFolderList.left,
  2843.                               rFolderList.top,
  2844.                               rFolderList.right - rFolderList.left,
  2845.                               rFolderList.bottom - rFolderList.top,
  2846.                               TRUE);
  2847.  
  2848.     TRect rActualFolderList = FolderList->GetClientRect();
  2849.     cyFolderList = rActualFolderList.bottom - rActualFolderList.top;
  2850.  
  2851.     FolderList->ShowWindow(SW_SHOWNORMAL);
  2852.  
  2853.     // Splitter Rectangle -- Used to re-size two lists--like a splitter window
  2854.     rSplitter.left = rFolderList.right - 5 * cxBorder;
  2855.     rSplitter.top = rFolderList.top;
  2856.     rSplitter.right = rSplitter.left + 10 * cxBorder;
  2857.     rSplitter.bottom = rFolderList.bottom;
  2858.  
  2859.     // Column Header (Right)
  2860.     rFileListHdr.left = rSplitter.right + cxBorder;
  2861.     rFileListHdr.top = rFolderListHdr.top;
  2862.     rFileListHdr.right = cxWin - 2 * cxBorder;
  2863.     rFileListHdr.bottom = rFolderListHdr.bottom;
  2864.  
  2865.     // Right Listbox (Documents/Files)
  2866.     rFileList.left = rFileListHdr.left;
  2867.     rFileList.top = rFolderList.top;
  2868.     rFileList.right = rFileListHdr.right;
  2869.     rFileList.bottom = rFolderList.bottom;
  2870.  
  2871.     FileList->MoveWindow(rFileList.left,
  2872.                                 rFileList.top,
  2873.                                 rFileList.right - rFileList.left,
  2874.                                 rFileList.bottom - rFileList.top,
  2875.                                 TRUE);
  2876.  
  2877.     TRect rActualFileList = FileList->GetClientRect();
  2878.     cyFileList = rActualFileList.bottom - rActualFileList.top;
  2879.  
  2880.     FileList->ShowWindow(SW_HIDE);
  2881.     FileList->ShowWindow(SW_SHOWNORMAL);
  2882.  
  2883.     FileList->InvalidateRect(rActualFileList);
  2884.  
  2885.     Invalidate();
  2886. }
  2887.  
  2888. // TreeView / ListView emulation methods start here.
  2889. int DFrame::AddTreeViewItem(TListBox* pLB, TREEVIEW_ITEM& TreeViewItem, int nPos)
  2890. {
  2891.     // Adds new tree item at specified position or if -1, appends item to list.
  2892.     assert(pLB);
  2893.  
  2894.     TREEVIEW_ITEM *pNewItem;
  2895.  
  2896.     pNewItem = new TREEVIEW_ITEM;
  2897.  
  2898.     if(!pNewItem)
  2899.         return -1;  // Failed.
  2900.  
  2901.     memcpy(pNewItem, &TreeViewItem, sizeof(TREEVIEW_ITEM));
  2902.  
  2903.     int nNewIndex = pLB->InsertString("NA", nPos);   // We don't use strings for owner-draw items.
  2904.  
  2905.     TRect rNone(-1,-1,-1,-1);
  2906.  
  2907.     if(nNewIndex > -1)
  2908.     {
  2909.         pLB->SetItemData(nNewIndex, (ULONG)(LPSTR)pNewItem);
  2910.         pLB->SetItemHeight(nNewIndex, CYLBHEIGHT);
  2911.         return nNewIndex;
  2912.     }
  2913.     else
  2914.     {
  2915.         MessageBox("Can't add item to list.", "Too Many List Items", MB_OK | MB_ICONSTOP);
  2916.         return -1;
  2917.     }
  2918. }
  2919.  
  2920. int DFrame::AddListViewItem(TListBox* pLB, FILEENTRY *ListViewItem, int nPos)
  2921. {
  2922.     // Adds new 'list view' item at specified position or if -1, appends item to list.
  2923.     assert(pLB);
  2924.  
  2925.     int nNewIndex;
  2926.  
  2927.     if(!ListViewItem)
  2928.         MessageBox("Bad ListViewItem in AddListViewItem!", "Error", MB_ICONEXCLAMATION);
  2929.  
  2930.     // Write text inside string--we could save memory by just writing the number.
  2931.     nNewIndex = pLB->InsertString("NA", nPos);
  2932.  
  2933.     if(nNewIndex > -1)
  2934.     {
  2935.         pLB->SetItemData(nNewIndex, (ULONG)(LPSTR)ListViewItem);
  2936.         pLB->SetItemHeight(nNewIndex, CYLBHEIGHT);
  2937.         return nNewIndex;
  2938.     }
  2939.     else
  2940.     {
  2941.         MessageBox("Can't add item to list.", "Too Many List Items", MB_OK | MB_ICONSTOP);
  2942.         return -1;
  2943.     }
  2944. }
  2945.  
  2946. LRESULT DFrame::DoDrawItem(WPARAM wParam, LPARAM lParam)
  2947. {
  2948.     // The OS/2 OWNERITEM structure contains these fields:
  2949.     //    HWND    hwnd;
  2950.     //        HPS     hps;
  2951.     //        ULONG   fsState;
  2952.     //        ULONG   fsAttribute;
  2953.     //        ULONG   fsStateOld;
  2954.     //        ULONG   fsAttributeOld;
  2955.     //        RECTL   rclItem;
  2956.     //        LONG    idItem; // This field contains idItem for menus, iItem for listboxes.
  2957.     //        ULONG   hItem;
  2958.     POWNERITEM pItem = (POWNERITEM)lParam;
  2959.  
  2960.     const int MAX_NODES = 256;
  2961.     int NodesFromRoot[256];
  2962.  
  2963.     TRect rItem;
  2964.     TRect rText;
  2965.  
  2966.     string strText;
  2967.  
  2968.     TSize sizeText;
  2969.  
  2970.     int nThisImage;
  2971.  
  2972.     int ctrlId = wParam;
  2973.  
  2974.     int i;
  2975.  
  2976.     // Just in case our background has changed.
  2977.     rgbLBBackground = WinQuerySysColor(HWindow,
  2978.                                                   SYSCLR_ENTRYFIELD,
  2979.                                                   0);
  2980.  
  2981.     TBrush *brBackground = new TBrush(TColor(rgbLBBackground));
  2982.     TPen *penBackground = new TPen(TColor(rgbLBBackground));
  2983.  
  2984.     if(ctrlId == IDC_DIRLIST)
  2985.     {
  2986.         // Folder List (TreeView) processing:
  2987.  
  2988.         // The TREEVIEW_ITEM structure contains these fields:
  2989.         //int nListBoxIndex;  // Index # of this entry.
  2990.         //int nLevel;         // In hierarchical list, this is the level of this entry
  2991.         //int nExpandCode;    // 0 = Nothing to expand, 1 == Can Expand [+], 2 Already Expanded [-]
  2992.         //int bIsEndOfLevel;
  2993.         //int iImage;
  2994.         //int iSelectedImage;
  2995.         //LPSTR lpszDirText;
  2996.         //int nTextLen;
  2997.  
  2998.         // Draw item with or without highlight with appropriate levels information
  2999.         TREEVIEW_ITEM *tvi = (TREEVIEW_ITEM *) FolderList->GetItemData(pItem->idItem);
  3000.         if(!tvi)
  3001.         {
  3002.             delete brBackground;
  3003.             delete penBackground;
  3004.             return TRUE;
  3005.         }
  3006.  
  3007.         int nLevelCount = tvi->nLevel - 2;
  3008.         assert(nLevelCount < MAX_NODES);
  3009.         for(TREEVIEW_ITEM *tviThis = (TREEVIEW_ITEM *)tvi->Parent;
  3010.                 tviThis != NULL && nLevelCount > -1; tviThis = (TREEVIEW_ITEM *)tviThis->Parent)
  3011.         {
  3012.             NodesFromRoot[nLevelCount] = tviThis->bIsEndOfLevel;
  3013.             nLevelCount--;
  3014.         }
  3015.  
  3016.         // Get a device context for this control.
  3017.         TClientDC dc(pItem->hwnd);
  3018.  
  3019.         // Draw with listbox font.
  3020.         if(pfontLB)
  3021.             dc.SelectObject(*pfontLB);
  3022.  
  3023.         // Get current dimensions of the Folder List listbox.
  3024.         TRect rActualFolder = FolderList->GetClientRect();
  3025.  
  3026.         // Calculate the dimensions of this listbox item.
  3027.         rItem.Set(pItem->rclItem.xLeft,
  3028.                      rActualFolder.bottom - rActualFolder.top - pItem->rclItem.yTop,                          pItem->rclItem.xRight,
  3029.                      rActualFolder.bottom - rActualFolder.top - pItem->rclItem.yBottom);
  3030.  
  3031.         // Clear entry first.
  3032.         dc.SelectObject(*brBackground);
  3033.         dc.SelectObject(*penBackground);
  3034.         dc.Rectangle(rItem);
  3035.  
  3036.         // Draw hierarchy levels as required...
  3037.         int cxStart = 0;
  3038.  
  3039.         dc.SelectObject(*ConnectorPen);
  3040.  
  3041.         for(int i = 0; i < tvi->nLevel; i++)
  3042.         {
  3043.             if(i == 0)
  3044.                 cxStart = rItem.left + 9;
  3045.             else
  3046.                 cxStart += 20;
  3047.  
  3048.             // If not last time, draw this line.
  3049.             if(i < tvi->nLevel - 1)
  3050.             {
  3051.                 if(!NodesFromRoot[i])
  3052.                 //if(!(i == tvi->nLevel - 2 && tvi->Parent && ((TREEVIEW_ITEM *)tvi->Parent)->bIsEndOfLevel))
  3053.                 {
  3054.                     // Draw connectors to other nodes in level(s).
  3055.                     // The special case is an expanded node that is the last in its level.
  3056.                     dc.MoveTo(cxStart, rItem.top);
  3057.                     dc.LineTo(cxStart, rItem.bottom);
  3058.                 }
  3059.             }
  3060.         }
  3061.  
  3062.         // Last connector is more work...
  3063.         if(cxStart == 0)
  3064.             cxStart = rItem.left + 9;
  3065.  
  3066.         int cyMid = (rItem.top + rItem.bottom) / 2;
  3067.  
  3068.         dc.MoveTo(cxStart, rItem.top);
  3069.         if(tvi->bIsEndOfLevel)
  3070.             dc.LineTo(cxStart, cyMid);
  3071.         else
  3072.             dc.LineTo(cxStart, rItem.bottom);
  3073.  
  3074.         dc.MoveTo(cxStart, cyMid);
  3075.         dc.LineTo(cxStart + 11, cyMid);
  3076.  
  3077.         // If this node is expandable or collapsible, draw a box.
  3078.         if(tvi->nExpandCode == 1 || tvi->nExpandCode == 2)
  3079.         {
  3080.             dc.SelectObject(*SolidConnectorPen);
  3081.             dc.SelectObject(*brBackground);
  3082.  
  3083.             dc.Rectangle(cxStart - 4,
  3084.                              cyMid - 4,
  3085.                              cxStart + 4,
  3086.                              cyMid + 4);
  3087.  
  3088.             // Draw [-]
  3089.             dc.SetPixel(cxStart - 2, cyMid, TColor(0,0,0));
  3090.             dc.SetPixel(cxStart - 1, cyMid, TColor(0,0,0));
  3091.             dc.SetPixel(cxStart, cyMid, TColor(0,0,0));
  3092.             dc.SetPixel(cxStart + 1, cyMid, TColor(0,0,0));
  3093.             dc.SetPixel(cxStart + 2, cyMid, TColor(0,0,0));
  3094.  
  3095.             if(tvi->nExpandCode == 1)  // Draw pixels for additional [+]
  3096.             {
  3097.                 dc.SetPixel(cxStart, cyMid - 2, TColor(0,0,0));
  3098.                 dc.SetPixel(cxStart, cyMid - 1, TColor(0,0,0));
  3099.                 dc.SetPixel(cxStart, cyMid + 1, TColor(0,0,0));
  3100.                 dc.SetPixel(cxStart, cyMid + 2, TColor(0,0,0));
  3101.             }
  3102.         }
  3103.  
  3104.         // Measure our current text.
  3105.         sizeText = dc.GetTextExtent(tvi->lpszDirText, strlen(tvi->lpszDirText));
  3106.  
  3107.         rText.Set(rItem.left + cxStart + 30,
  3108.                      rItem.top + 2,
  3109.                      rItem.left + cxStart + 30 + sizeText.cx + 2,
  3110.                      rItem.top + sizeText.cy + 3);
  3111.  
  3112.         if(pItem->fsState == TRUE) // Highlighted
  3113.         {
  3114.             // Highlight text only in blue
  3115.             dc.SetBkColor(TColor(0,0,255));
  3116.             dc.SetTextColor(TColor(255,255,255));  // Text in white.
  3117.             // Draw selected image.
  3118.             nThisImage = tvi->iSelectedImage;
  3119.  
  3120.             // Draw text next to image.
  3121.             dc.ExtTextOut(rText.left + 1,
  3122.                               rText.top + 1,
  3123.                               ETO_OPAQUE,
  3124.                               &rText, tvi->lpszDirText, strlen(tvi->lpszDirText), NULL);
  3125.         }
  3126.         else
  3127.         {
  3128.             // Draw normal text and normal image..
  3129.             dc.SetBkColor(TColor(rgbLBBackground));
  3130.             dc.SetTextColor(TColor(0,0,0));  // Text in black.
  3131.             nThisImage = tvi->iImage;
  3132.             dc.TextOut(rText.left + 1, rText.top + 1, tvi->lpszDirText, strlen(tvi->lpszDirText));
  3133.         }
  3134.  
  3135.         DrawImage(dc, nThisImage, cxStart + 11, rItem.top + 1);  // +4
  3136.  
  3137.         if(tvi->nExpandCode == 2)
  3138.         {
  3139.             // Extra connector under bitmap for expanded levels.
  3140.             dc.SelectObject(*ConnectorPen);
  3141.             cxStart += 20;
  3142.             dc.MoveTo(cxStart, cyMid + 7);
  3143.             dc.LineTo(cxStart, rItem.bottom);
  3144.         }
  3145.  
  3146.         dc.RestoreObjects();
  3147.  
  3148.         // Tell OS/2 not to draw highlighting.
  3149.         pItem->fsState = pItem->fsStateOld;
  3150.         // Tell OS/2 not to draw focus.
  3151.         pItem->fsAttribute = pItem->fsAttributeOld;
  3152.  
  3153.         delete brBackground;
  3154.         delete penBackground;
  3155.  
  3156.         return TRUE;
  3157.     }
  3158.     else if(ctrlId == IDC_FILELIST)
  3159.     {
  3160.         // Files List (ListView) processing:
  3161.  
  3162.         // The FILEENTRY class contains the following relevant members:
  3163.         //   long lFileSize;
  3164.         //   unsigned long  ulFileAttrib;
  3165.         //   unsigned short uFileTime;
  3166.         //   unsigned short uFileDate;
  3167.         //   char szFileName[256];
  3168.         //   char szExt[4];  // File Extension
  3169.         //   int nType;   // 1 for Directory, 2 for .EXE, 3 for .CMD, 4 for .BAT, 5 for .COM and 6 for document.
  3170.         //   int iImage;    // Which bitmap/-image to draw.
  3171.  
  3172.         // Draw list view item with appropriate icon.
  3173.         FILEENTRY *lvi = (FILEENTRY *) FileList->GetItemData(pItem->idItem);
  3174.         if(!lvi)
  3175.         {
  3176.             delete brBackground;
  3177.             delete penBackground;
  3178.             return TRUE;
  3179.         }
  3180.  
  3181.         // Get device context for the Files List listbox.
  3182.         TClientDC dc(pItem->hwnd);
  3183.  
  3184.         // Draw with listbox font.
  3185.         if(pfontLB)
  3186.             dc.SelectObject(*pfontLB);
  3187.  
  3188.         // Get current dimensions of the Folder List listbox.
  3189.         TRect rActualFileList = FileList->GetClientRect();
  3190.  
  3191.         // Calculate our height.
  3192.         cyFileList = rActualFileList.bottom - rActualFileList.top;
  3193.  
  3194.         // Determine the size of this item.
  3195.         rItem.Set(pItem->rclItem.xLeft,
  3196.                      rActualFileList.bottom - rActualFileList.top - pItem->rclItem.yTop,
  3197.                      pItem->rclItem.xRight,
  3198.                      rActualFileList.bottom - rActualFileList.top - pItem->rclItem.yBottom);
  3199.  
  3200.         // Clear entry first.
  3201.         dc.SelectObject(*brBackground);
  3202.         dc.SelectObject(*penBackground);
  3203.  
  3204.         dc.Rectangle(rItem);
  3205.  
  3206.         int cxStart = 2;
  3207.  
  3208.         sizeText = dc.GetTextExtent(lvi->szFileName, strlen(lvi->szFileName));
  3209.  
  3210.         // Get the dimensions of the text required for our filename / directory name.
  3211.         rText.Set(rItem.left + cxStart + 20,
  3212.                      rItem.top + 2,
  3213.                      rItem.left + cxStart + 20 + sizeText.cx + 2,
  3214.                      rItem.top + sizeText.cy + 3);
  3215.  
  3216.         // Draw the image next to our text
  3217.         DrawImage(dc, lvi->iImage, cxStart, rItem.top + 1, 0, TRUE);  // + 4
  3218.  
  3219.         if(pItem->fsState == TRUE) // Highlighted
  3220.         {
  3221.             // Highlight text in blue
  3222.             dc.SetBkColor(TColor(0,0,255));
  3223.             dc.SetTextColor(TColor(255,255,255));  // Text in white.
  3224.             // Draw text next to image.
  3225.             dc.ExtTextOut(rText.left + 1,
  3226.                               rText.top + 1,
  3227.                               ETO_OPAQUE,
  3228.                               &rText, lvi->szFileName, strlen(lvi->szFileName), NULL);
  3229.         }
  3230.         else
  3231.         {
  3232.             // Draw normal text.
  3233.             dc.SetBkColor(TColor(rgbLBBackground));
  3234.             dc.SetTextColor(TColor(0,0,0));  // Text in black.
  3235.             dc.TextOut(rText.left + 1, rText.top + 1, lvi->szFileName, strlen(lvi->szFileName));
  3236.         }
  3237.  
  3238.         // Check which file details are selected (if any), and draw them in normal text.
  3239.         dc.SetBkColor(TColor(rgbLBBackground));
  3240.         dc.SetTextColor(TColor(0,0,0));  // Text in black.
  3241.  
  3242.         string strDisplay;
  3243.  
  3244.         int cxNextPos = rText.left + cxName;
  3245.  
  3246.         if(bShowSize)
  3247.         {
  3248.             // Then display file size (except for folders!).
  3249.             if(lvi->nType != 1)
  3250.             {
  3251.                 strDisplay = GetFileSizeAsStr(lvi->lFileSize);
  3252.                 dc.TextOut(cxNextPos, rText.top + 1, strDisplay.c_str(), strDisplay.length());
  3253.             }
  3254.             // Advance to next 'column' in list.
  3255.             cxNextPos += cxSize;
  3256.         }
  3257.         if(bShowTimeStamp)
  3258.         {
  3259.             // Then display file's date/time of last modification.
  3260.             char szTemp[40];
  3261.             strDisplay = GetFileTimeStampAsString(szTemp, lvi->uFileDate, lvi->uFileTime);
  3262.             dc.TextOut(cxNextPos, rText.top + 1, strDisplay.c_str(), strDisplay.length());
  3263.             // Advance to next 'column' in list.
  3264.             cxNextPos += cxTimeStamp;
  3265.         }
  3266.         if(bShowAttr)
  3267.         {
  3268.             // Check for each type of attribute--move over the same
  3269.             // distance for each whether or not each attribute is set or not.
  3270.             // This ensures alignment of each attribute type.
  3271.  
  3272.             // Check and display 'System' attribute.
  3273.             if((lvi->ulFileAttrib & FA_SYSTEM) != 0)
  3274.                 dc.TextOut(cxNextPos, rText.top + 1, "S", 1);
  3275.  
  3276.             // Check and display 'Hidden' attribute.
  3277.             if((lvi->ulFileAttrib & FA_HIDDEN) != 0)
  3278.                 dc.TextOut(cxNextPos + cxAttribute, rText.top + 1, "H", 1);
  3279.  
  3280.             // Check and display 'Read-Only' attribute.
  3281.             if((lvi->ulFileAttrib & FA_RDONLY) != 0)
  3282.                 dc.TextOut(cxNextPos + (cxAttribute * 2), rText.top + 1, "R", 1);
  3283.  
  3284.             // Check and display 'Archive' attribute.
  3285.             if((lvi->ulFileAttrib & FA_ARCH) != 0)
  3286.                 dc.TextOut(cxNextPos + (cxAttribute * 3), rText.top + 1, "A", 1);
  3287.  
  3288.             // Check and display 'Directory' attribute.
  3289.             if((lvi->ulFileAttrib & FA_DIREC) != 0)
  3290.                 dc.TextOut(cxNextPos + (cxAttribute * 4), rText.top + 1, "D", 1);
  3291.         }
  3292.         dc.RestoreObjects();
  3293.  
  3294.         // Tell OS/2 not to draw highlighting.
  3295.         pItem->fsState = pItem->fsStateOld;
  3296.         // Tell OS/2 not to draw focus.
  3297.         pItem->fsAttribute = pItem->fsAttributeOld;
  3298.  
  3299.         delete brBackground;
  3300.         delete penBackground;
  3301.  
  3302.         return TRUE;
  3303.     }
  3304.     return 0L;
  3305. }
  3306.  
  3307. void DFrame::EvRButtonDown(UINT keys, TPoint& point)
  3308. {
  3309.     nMouseBtnDownCode = RIGHT_BTN;
  3310.     EvLButtonDown(keys, point);
  3311. }
  3312.  
  3313. LRESULT DFrame::DoDragOver(WPARAM wParam, LPARAM lParam)
  3314. {
  3315.     lParam;
  3316.     return ((LRESULT)DragOver(WinQueryAnchorBlock(HWindow),
  3317.                                       (MPARAM)wParam,
  3318.                                       szCurrentListViewDir));
  3319. }
  3320.  
  3321. LRESULT DFrame::DoDragLeave(WPARAM wParam, LPARAM lParam)
  3322. {
  3323.     wParam;
  3324.     lParam;
  3325.     return ((LRESULT)DragLeave());
  3326. }
  3327.  
  3328. LRESULT DFrame::DoDropHelp(WPARAM wParam, LPARAM lParam)
  3329. {
  3330.     lParam;
  3331.     return ((LRESULT)DropHelp(HWindow, (MPARAM)wParam));
  3332. }
  3333.  
  3334. LRESULT DFrame::DoDrop(WPARAM wParam, LPARAM lParam)
  3335. {
  3336.     lParam;
  3337.     return ((LRESULT)Drop(WinQueryAnchorBlock(HWindow),
  3338.                                 HWindow,
  3339.                                 (MPARAM)wParam,
  3340.                                 szCurrentListViewDir));
  3341. }
  3342.  
  3343. void CustomListBox::EvMouseMove(UINT keys, TPoint& point)
  3344. {
  3345.     // Another OS/2 / OWL anomaly--mouse move messages are not delivered
  3346.     // to the DFrame window when the left mouse button is pressed.
  3347.     // The solution here is to use a derived class that will
  3348.     // receive this message and call the parent's member function.
  3349.     if(pGlobalParent && bForwarding)
  3350.     {
  3351.         ((DFrame *)pGlobalParent)->EvMouseMove(keys, point);
  3352.     }
  3353.     DefaultProcessing();
  3354. }
  3355.  
  3356. class DApp : public TApplication
  3357. {
  3358.     public:
  3359.         DApp();  // Our constructor
  3360.         void InitMainWindow();
  3361. };
  3362.  
  3363.  
  3364. class CustomDecFrame : public TDecoratedFrame
  3365. {
  3366. private:
  3367.     int cxMin;
  3368.     int cyMin;
  3369.  
  3370. public:
  3371.     CustomDecFrame(TWindow *pParent, char *pTitle, TWindow *pClient) :
  3372.         TDecoratedFrame(pParent, pTitle, pClient) {
  3373.             cxMin = WinQuerySysValue(HWND_DESKTOP, SV_CXICON);
  3374.             cyMin = WinQuerySysValue(HWND_DESKTOP, SV_CYICON);
  3375.         }
  3376.  
  3377.     // Inline for speed here...
  3378.     BOOL PreProcessMsg(MSG &msg) {
  3379.         if(msg.message == WM_PAINT)
  3380.         {
  3381.             // Remove status bar if we're iconized.
  3382.             // This is required to overcome an apparent problem in OWL
  3383.             // where a TDecoratedFrame object paints over the icon when minimized.
  3384.             TRect r;
  3385.             GetClientRect(r);
  3386.  
  3387.             if(((r.right - r.left) <= cxMin) && ((r.bottom - r.top) <= cyMin))
  3388.             {
  3389.                 // Erase status bar;
  3390.                 if(pGlobalStatus)
  3391.                     pGlobalStatus->ShowWindow(SW_HIDE);
  3392.             }
  3393.             else
  3394.             {
  3395.                 // Paint as before.
  3396.                 // Show status bar.
  3397.                 if(pGlobalParent)
  3398.                     pGlobalParent->ShowWindow(SW_SHOW);
  3399.             }
  3400.         }
  3401.         return TDecoratedFrame::PreProcessMsg(msg);
  3402.     }
  3403. };
  3404.  
  3405. //*****************************************************************************
  3406. // Define our DApp class methods below.
  3407. //*****************************************************************************
  3408.  
  3409. DApp::DApp() : TApplication()
  3410. {
  3411. }
  3412.  
  3413. void DApp::InitMainWindow()
  3414. {
  3415.     // Do some initializing...
  3416.     DFrame *MyFrame = new DFrame(NULL);
  3417.     MyFrame->Attr.AccelTable = ID_MAIN;
  3418.  
  3419.     //TDecoratedFrame *pBaseFrame = new TDecoratedFrame(0, "Warp Cabinet", MyFrame);
  3420.     CustomDecFrame *pBaseFrame = new CustomDecFrame(0, "Warp Cabinet", MyFrame);
  3421.  
  3422.     pBaseFrame->AssignMenu(TResId(ID_MAIN));
  3423.  
  3424.     // Let us draw our icon in minimized state.
  3425.     pBaseFrame->SetIcon(this, ID_MAIN);
  3426.  
  3427.     SetMainWindow(pBaseFrame);
  3428.  
  3429.     // Create status bar on bottom of our window.
  3430.     TStatusBar* sb = new TStatusBar(0, TGadget::Recessed);
  3431.     sb->Attr.Style |= WS_CHILD;
  3432.     pBaseFrame->Insert(*sb, TDecoratedFrame::Bottom);
  3433.  
  3434.     TTextGadget *stattext = new TTextGadget(0, TGadget::Recessed, TTextGadget::Left, 70);
  3435.  
  3436.     sb->Insert(*stattext, TStatusBar::Before);
  3437.     EnableCtl3d(TRUE);
  3438.  
  3439.     MyFrame->SetStatusTextCtrl(stattext);
  3440.     MyFrame->SetFrame(pBaseFrame);
  3441.  
  3442.     hptrCopy = (HPOINTER)LoadCursor(ID_COPY_DOCS);
  3443.     hptrMove = (HPOINTER)LoadCursor(ID_MOVE_DOCS);
  3444.  
  3445.     pGlobalStatus = sb;
  3446. }
  3447.  
  3448. // Entry point to an OWL application.
  3449. OwlMain(int, char **)
  3450. {
  3451.     DApp WarpFilerApp;  // Create our application
  3452.     int rc;
  3453.  
  3454.     rc = WarpFilerApp.Run();
  3455.  
  3456.     return rc;
  3457. }
  3458.  
  3459.